Add Vertex Crease operator to vertex context menu #109146

Merged
Pratik Borhade merged 5 commits from persun/blender:test into main 2023-09-20 08:58:25 +02:00
260 changed files with 7696 additions and 6253 deletions
Showing only changes of commit e03d225dc4 - Show all commits

View File

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

View File

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

5
extern/xdnd/xdnd.c vendored
View File

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

View File

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

View File

@ -61,6 +61,8 @@ bool HIPRTDeviceQueue::enqueue(DeviceKernel kernel,
0),
"enqueue");
debug_enqueue_end();
return !(hiprt_device_->have_error());
}

View File

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

View File

@ -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<Stack> traversal(kernel_data.device_bvh, \
ray_hip, \
stack, \
@ -61,10 +61,10 @@ struct LocalPayload {
hiprtTraversalHintDefault, \
&payload, \
kernel_params.FUNCTION_TABLE, \
RAY_TYPE); \
hiprtSceneTraversalAnyHitCustomStack<Stack> 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<Stack> traversal(kernel_data.device_bvh, \
ray_hip, \
stack, \
@ -72,9 +72,8 @@ struct LocalPayload {
hiprtTraversalHintDefault, \
&payload, \
kernel_params.FUNCTION_TABLE, \
RAY_TYPE); \
hiprtSceneTraversalClosestCustomStack<Stack> 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,

View File

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

View File

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

View File

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

View File

@ -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<in_volume_segment>(
kg, rand_uv, time, P, object_receiver, bounce, path_flag, index, 0, pdf_selection, ls);
return light_sample<in_volume_segment>(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)

View File

@ -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<in_volume_segment>(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<in_volume_segment>(kg, light, rand, P, path_flag, ls)) {
if (!light_sample<in_volume_segment>(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;
}
}

View File

@ -8,68 +8,123 @@
CCL_NAMESPACE_BEGIN
template<bool in_volume_segment>
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;
float3 lightN = P - klight->co;
const float d_sq = len_squared(lightN);
const float d = sqrtf(d_sq);
lightN /= d;
if (radius > 0.0f) {
ls->P += disk_light_sample(lightN, rand) * radius;
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);
float dist_point_to_centroid;
point_to_centroid = safe_normalize_len(centroid - P, &dist_point_to_centroid);
const float radius = klight->spot.radius;
const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance));
cos_theta_u = min_distance / hypotenus;
distance = make_float2(hypotenus, min_distance);
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;
}

View File

@ -338,7 +338,7 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
#endif
{
return light_distribution_sample<true>(
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<false>(
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -584,13 +584,14 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
std::string title = window->getTitle();
char *ctitle = (char *)malloc(title.size() + 1);
const size_t ctitle_size = title.size() + 1;
char *ctitle = (char *)malloc(ctitle_size);
if (ctitle == nullptr) {
return nullptr;
}
strcpy(ctitle, title.c_str());
memcpy(ctitle, title.c_str(), ctitle_size);
return ctitle;
}

View File

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

View File

@ -2190,12 +2190,14 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
owner = XGetSelectionOwner(m_display, sseln);
if (owner == win) {
if (sseln == m_atom.CLIPBOARD) {
sel_buf = (char *)malloc(strlen(txt_cut_buffer) + 1);
strcpy(sel_buf, txt_cut_buffer);
size_t sel_buf_size = strlen(txt_cut_buffer) + 1;
sel_buf = (char *)malloc(sel_buf_size);
memcpy(sel_buf, txt_cut_buffer, sel_buf_size);
return sel_buf;
}
sel_buf = (char *)malloc(strlen(txt_select_buffer) + 1);
strcpy(sel_buf, txt_select_buffer);
size_t sel_buf_size = strlen(txt_select_buffer) + 1;
sel_buf = (char *)malloc(sel_buf_size);
memcpy(sel_buf, txt_select_buffer, sel_buf_size);
return sel_buf;
}
if (owner == None) {
@ -2289,8 +2291,9 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
free((void *)txt_cut_buffer);
}
txt_cut_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_cut_buffer, buffer);
size_t buffer_size = strlen(buffer) + 1;
txt_cut_buffer = (char *)malloc(buffer_size);
memcpy(txt_cut_buffer, buffer, buffer_size);
}
else {
XSetSelectionOwner(m_display, m_atom.PRIMARY, m_window, CurrentTime);
@ -2299,8 +2302,9 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
free((void *)txt_select_buffer);
}
txt_select_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_select_buffer, buffer);
size_t buffer_size = strlen(buffer) + 1;
txt_select_buffer = (char *)malloc(buffer_size);
memcpy(txt_select_buffer, buffer, buffer_size);
}
if (owner != m_window) {

View File

@ -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 <tessil@gmx.com>
** 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

View File

@ -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 @@ class Mesh(bpy_types.ID):
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 @@ class Mesh(bpy_types.ID):
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__ = ()

View File

@ -246,6 +246,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
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)

View File

@ -250,13 +250,10 @@ class NODE_OT_tree_path_parent(Operator):
class NodePanelOperator():
@classmethod
def poll(cls, context):
snode = context.space_data
if snode is None:
space = context.space_data
if not space or space.type != 'NODE_EDITOR' or not space.edit_tree:
return False
tree = snode.edit_tree
if tree is None:
return False
if tree.is_embedded_data:
if space.edit_tree.is_embedded_data:
return False
return True

View File

@ -398,7 +398,7 @@ def lightmap_uvpack(
# Since the boxes are sized in powers of 2, we can neatly group them into bigger squares
# this is done hierarchically, so that we may avoid running the pack function
# on many thousands of boxes, (under 1k is best) because it would get slow.
# Using an off and even dict us useful because they are packed differently
# Using an odd and even dict is useful because they are packed differently
# where w/h are the same, their packed in groups of 4
# where they are different they are packed in pairs
#

View File

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

View File

@ -87,8 +87,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
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)

View File

@ -2431,7 +2431,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_experimental_compositors"}, ("blender/blender/issues/88150", "#88150")),
({"property": "enable_eevee_next"}, ("blender/blender/issues/93220", "#93220")),
({"property": "enable_workbench_next"}, ("blender/blender/issues/101619", "#101619")),
({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/40", "Grease Pencil 3.0")),
({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/6", "Grease Pencil 3.0")),
({"property": "enable_overlay_next"}, ("blender/blender/issues/102179", "#102179")),
),
)

View File

@ -748,6 +748,14 @@ class VIEW3D_HT_header(Header):
).domain = 'CURVE'
# Grease Pencil
if obj and obj.type == 'GREASEPENCIL':
# Select mode for Editing
if object_mode == 'EDIT':
row = layout.row(align=True)
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='POINT')
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='STROKE')
# Grease Pencil (legacy)
if obj and obj.type == 'GPENCIL' and context.gpencil_data:
gpd = context.gpencil_data
@ -2024,6 +2032,7 @@ class VIEW3D_MT_select_edit_gpencil(Menu):
def draw(self, context):
if not context.preferences.experimental.use_grease_pencil_version3:
self.draw_legacy(context)
return
layout = self.layout
@ -2034,6 +2043,7 @@ class VIEW3D_MT_select_edit_gpencil(Menu):
layout.separator()
layout.operator("grease_pencil.select_linked", text="Linked")
layout.operator("grease_pencil.select_random", text="Random")
layout.separator()
@ -3055,8 +3065,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")
@ -3592,9 +3602,6 @@ class VIEW3D_MT_face_sets_init(Menu):
props = layout.operator("sculpt.face_sets_init", text="By Sharp Edges")
props.mode = 'SHARP_EDGES'
props = layout.operator("sculpt.face_sets_init", text="By Face Maps")
props.mode = 'FACE_MAPS'
class VIEW3D_MT_random_mask(Menu):
bl_label = "Random Mask"

View File

@ -18,8 +18,9 @@ class MyPanel(bpy.types.Panel):
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",
)

View File

@ -206,7 +206,7 @@ typedef struct GlyphBLF {
/**
* X and Y bearing of the glyph.
* The X bearing is from the origin to the glyph left bbox edge.
* The X bearing is from the origin to the glyph left bounding-box edge.
* The Y bearing is from the baseline to the top of the glyph edge.
*/
int pos[2];

View File

@ -559,7 +559,9 @@ void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
/* context.selected_pose_bones */
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \
for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \
for (bPoseChannel *_pchan = (bPoseChannel *)(_ob)->pose->chanbase.first; _pchan; \
_pchan = _pchan->next) \
{ \
if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone) && \
((_pchan)->bone->flag & BONE_SELECTED)) \
{

View File

@ -930,7 +930,7 @@ void gather_attributes(AttributeAccessor src_attributes,
MutableAttributeAccessor dst_attributes);
/**
* Copy attribute values from groups groups defined by \a src_offsets to groups defined by \a
* Copy attribute values from groups defined by \a src_offsets to groups defined by \a
* dst_offsets. The group indices are gathered to the result by \a selection. The size of each
* source and result group must be the same.
*/

View File

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

View File

@ -71,8 +71,7 @@ class Layer;
/**
* A TreeNode represents one node in the layer tree.
* It can either be a layer or a group. The node has zero children if it is a layer or zero or
more
* children if it is a group.
* more children if it is a group.
*/
class TreeNode : public ::GreasePencilLayerTreeNode {
public:

View File

@ -93,13 +93,15 @@ void normals_calc_poly_vert(Span<float3> 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]);

View File

@ -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<int> allow_use_dirty_topology_cache = 0;
CacheMutex tree_zones_cache_mutex;
std::unique_ptr<node_tree_zones::TreeZones> tree_zones;
std::unique_ptr<bNodeTreeZones> tree_zones;
/** Only valid when #topology_cache_is_dirty is false. */
Vector<bNodeLink *> links;

View File

@ -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<TreeZone *> child_zones;
Vector<bNodeTreeZone *> child_zones;
/** Direct children nodes excluding nodes that belong to child zones. */
Vector<const bNode *> child_nodes;
/** Links that enter the zone through the zone border. */
Vector<const bNodeLink *> 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<std::unique_ptr<TreeZone>> zones;
Vector<TreeZone *> root_zones;
Vector<std::unique_ptr<bNodeTreeZone>> zones;
Vector<bNodeTreeZone *> root_zones;
Vector<const bNode *> 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<const bNodeTreeZone *> 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::node_tree_zones
} // namespace blender::bke
inline const blender::bke::bNodeTreeZones *bNodeTree::zones() const
{
return blender::bke::get_tree_zones(*this);
}

View File

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

View File

@ -39,7 +39,7 @@ typedef struct bMovieHandle {
void (*end_movie)(void *context_v);
/* Optional function. */
void (*get_movie_path)(char *filepath,
void (*get_movie_path)(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd,
bool preview,
const char *suffix);
@ -53,7 +53,7 @@ bMovieHandle *BKE_movie_handle_get(char imtype);
/**
* \note Similar to #BKE_image_path_from_imformat()
*/
void BKE_movie_filepath_get(char *filepath,
void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd,
bool preview,
const char *suffix);

View File

@ -65,7 +65,7 @@ int BKE_ffmpeg_append(void *context_v,
int recty,
const char *suffix,
struct ReportList *reports);
void BKE_ffmpeg_filepath_get(char *filepath,
void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd,
bool preview,
const char *suffix);

View File

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

View File

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

View File

@ -355,9 +355,9 @@ class BKE_armature_find_selected_bones_test : public testing::Test {
void SetUp() override
{
strcpy(bone1.name, "bone1");
strcpy(bone2.name, "bone2");
strcpy(bone3.name, "bone3");
STRNCPY(bone1.name, "bone1");
STRNCPY(bone2.name, "bone2");
STRNCPY(bone3.name, "bone3");
arm.bonebase = {nullptr, nullptr};
bone1.childbase = {nullptr, nullptr};

View File

@ -147,7 +147,7 @@ void BKE_blender_globals_init(void)
BKE_blender_globals_main_replace(BKE_main_new());
strcpy(G.ima, "//");
STRNCPY(G.ima, "//");
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_FLAG_SCRIPT_AUTOEXEC;

View File

@ -219,11 +219,13 @@ static void setup_app_userdef(BlendFileData *bfd)
}
}
/** Helper struct to manage IDs that are re-used across blendfile loading (i.e. moved from the old
* Main the the new one).
/**
* Helper struct to manage IDs that are re-used across blend-file loading (i.e. moved from the old
* Main the new one).
*
* NOTE: this is only used when actually loading a real .blend file, loading of memfile undo steps
* does not need it. */
* NOTE: this is only used when actually loading a real `.blend` file,
* loading of memfile undo steps does not need it.
*/
typedef struct ReuseOldBMainData {
Main *new_bmain;
Main *old_bmain;

View File

@ -1657,7 +1657,7 @@ BoidState *boid_new_state(BoidSettings *boids)
SNPRINTF(state->name, "State %i", state->id);
}
else {
strcpy(state->name, "State");
STRNCPY(state->name, "State");
}
state->rule_fuzziness = 0.5;

View File

@ -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<char *>(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

View File

@ -99,7 +99,7 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese
new_lineset->edge_types = lineset->edge_types;
new_lineset->exclude_edge_types = lineset->exclude_edge_types;
new_lineset->group = lineset->group;
strcpy(new_lineset->name, lineset->name);
STRNCPY(new_lineset->name, lineset->name);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)new_lineset->linestyle);
@ -187,7 +187,7 @@ FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain,
SNPRINTF(lineset->name, "LineSet %i", lineset_index + 1);
}
else {
strcpy(lineset->name, "LineSet");
STRNCPY(lineset->name, "LineSet");
}
BKE_freestyle_lineset_unique_name(config, lineset);

View File

@ -791,7 +791,7 @@ IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
/* NOTE(@ideasman42): Don't overwrite the data's name and type
* some functions might need this if they
* don't have a real ID, should be named elsewhere. */
// strcpy(id->name, "top_level_group");
// STRNCPY(id->name, "top_level_group");
}
return id->properties;
}

View File

@ -1165,7 +1165,7 @@ static char *get_rna_access(ID *id,
else if ((blocktype == ID_KE) && STREQ(actname, "Shape")) {
/* Actionified "Shape" IPO's -
* these are forced onto object level via the action container there... */
strcpy(buf, "data.shape_keys");
STRNCPY(buf, "data.shape_keys");
}
else {
/* Pose-Channel */

View File

@ -40,7 +40,7 @@ static void test_lattice_deform_init(LatticeDeformTestContext *ctx,
ctx->coords[index][2] = (rng->get_float() - 0.5f) * 10;
}
IDType_ID_LT.init_data(&ctx->lattice.id);
strcpy(ctx->lattice.id.name, "LTLattice");
STRNCPY(ctx->lattice.id.name, "LTLattice");
IDType_ID_OB.init_data(&ctx->ob_lattice.id);
ctx->ob_lattice.type = OB_LATTICE;
ctx->ob_lattice.data = &ctx->lattice;

View File

@ -1620,7 +1620,7 @@ bool BKE_id_new_name_validate(
result = BKE_main_namemap_get_name(bmain, id, name);
strcpy(id->name + 2, name);
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
id_sort_by_name(lb, id, NULL);
return result;
}
@ -2012,7 +2012,7 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
{
strcpy(name, id->name + 2);
BLI_strncpy(name, id->name + 2, MAX_ID_FULL_NAME);
if (ID_IS_LINKED(id)) {
const size_t idname_len = strlen(id->name + 2);
@ -2020,7 +2020,7 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa
name[idname_len] = separator_char ? separator_char : ' ';
name[idname_len + 1] = '[';
strcpy(name + idname_len + 2, id->lib->id.name + 2);
BLI_strncpy(name + idname_len + 2, id->lib->id.name + 2, MAX_ID_FULL_NAME - (idname_len + 2));
name[idname_len + 2 + libname_len] = ']';
name[idname_len + 2 + libname_len + 1] = '\0';
}

View File

@ -336,12 +336,7 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
{
MaskLayer *masklay = MEM_cnew<MaskLayer>(__func__);
if (name && name[0]) {
STRNCPY(masklay->name, name);
}
else {
strcpy(masklay->name, DATA_("MaskLayer"));
}
STRNCPY(masklay->name, name && name[0] ? name : DATA_("MaskLayer"));
BLI_addtail(&mask->masklayers, masklay);
@ -1011,12 +1006,7 @@ Mask *BKE_mask_new(Main *bmain, const char *name)
Mask *mask;
char mask_name[MAX_ID_NAME - 2];
if (name && name[0]) {
STRNCPY(mask_name, name);
}
else {
strcpy(mask_name, "Mask");
}
STRNCPY(mask_name, (name && name[0]) ? name : "Mask");
mask = mask_alloc(bmain, mask_name);
@ -2040,7 +2030,7 @@ void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
if (!BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id)) {
int len = strlen(point->parent.id->name);
char *name_copy = static_cast<char *>(MEM_mallocN(len + 1, "mask clipboard ID name"));
strcpy(name_copy, point->parent.id->name);
memcpy(name_copy, point->parent.id->name, len + 1);
BLI_ghash_insert(mask_clipboard.id_hash, point->parent.id, name_copy);
}
}

View File

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

View File

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

View File

@ -338,14 +338,16 @@ void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
*ract_uv_n = CustomData_get_active_layer(loopData, CD_PROP_FLOAT2);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
BLI_strncpy(
ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_PROP_FLOAT2);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
BLI_strncpy(
rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name, MAX_CUSTOMDATA_LAYER_NAME);
}
/* If active tangent not in tangent_names we take it into account */

View File

@ -367,7 +367,7 @@ void BKE_nlatrack_insert_before(ListBase *nla_tracks,
new_track->index = BLI_findindex(nla_tracks, new_track);
/* Must have unique name, but we need to seed this. */
strcpy(new_track->name, "NlaTrack");
STRNCPY(new_track->name, "NlaTrack");
BLI_uniquename(nla_tracks,
new_track,

View File

@ -3653,9 +3653,6 @@ void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
if (ntree->typeinfo->local_merge) {
ntree->typeinfo->local_merge(bmain, localtree, ntree);
}
ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
}

View File

@ -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<std::unique_ptr<TreeZone>> find_zone_nodes(
const bNodeTree &tree, TreeZones &owner, Map<const bNode *, TreeZone *> &r_zone_by_inout_node)
static Vector<std::unique_ptr<bNodeTreeZone>> find_zone_nodes(
const bNodeTree &tree,
bNodeTreeZones &owner,
Map<const bNode *, bNodeTreeZone *> &r_zone_by_inout_node)
{
Vector<std::unique_ptr<TreeZone>> zones;
Vector<std::unique_ptr<bNodeTreeZone>> zones;
for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationOutput")) {
auto zone = std::make_unique<TreeZone>();
auto zone = std::make_unique<bNodeTreeZone>();
zone->owner = &owner;
zone->index = zones.size();
zone->output_node = node;
@ -41,7 +43,7 @@ static Vector<std::unique_ptr<TreeZone>> find_zone_nodes(
for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
const auto &storage = *static_cast<NodeGeometrySimulationInput *>(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<std::unique_ptr<TreeZone>> find_zone_nodes(
}
struct ZoneRelation {
TreeZone *parent;
TreeZone *child;
bNodeTreeZone *parent;
bNodeTreeZone *child;
};
static Vector<ZoneRelation> get_direct_zone_relations(
const Span<std::unique_ptr<TreeZone>> all_zones,
const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
const BitGroupVector<> &depend_on_input_flag_array)
{
Vector<ZoneRelation> zone_relations;
/* Gather all relations, even the transitive once. */
for (const std::unique_ptr<TreeZone> &zone : all_zones) {
for (const std::unique_ptr<bNodeTreeZone> &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<ZoneRelation> get_direct_zone_relations(
}
static void update_zone_per_node(const Span<const bNode *> all_nodes,
const Span<std::unique_ptr<TreeZone>> all_zones,
const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
const BitGroupVector<> &depend_on_input_flag_array,
const Map<const bNode *, TreeZone *> &zone_by_inout_node,
const Map<const bNode *, bNodeTreeZone *> &zone_by_inout_node,
Map<int, int> &r_zone_by_node_id,
Vector<const bNode *> &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<const bNode *> all_nodes,
r_zone_by_node_id.add(node.identifier, parent_zone->index);
}
}
for (const MapItem<const bNode *, TreeZone *> item : zone_by_inout_node.items()) {
for (const MapItem<const bNode *, bNodeTreeZone *> 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<TreeZone *>(tree_zones.get_zone_by_socket(*link->fromsock));
TreeZone *to_zone = const_cast<TreeZone *>(tree_zones.get_zone_by_socket(*link->tosock));
bNodeTreeZone *from_zone = const_cast<bNodeTreeZone *>(
tree_zones.get_zone_by_socket(*link->fromsock));
bNodeTreeZone *to_zone = const_cast<bNodeTreeZone *>(
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<TreeZones> discover_tree_zones(const bNodeTree &tree)
static std::unique_ptr<bNodeTreeZones> discover_tree_zones(const bNodeTree &tree)
{
if (tree.has_available_link_cycle()) {
return {};
}
std::unique_ptr<TreeZones> tree_zones = std::make_unique<TreeZones>();
std::unique_ptr<bNodeTreeZones> tree_zones = std::make_unique<bNodeTreeZones>();
const Span<const bNode *> all_nodes = tree.all_nodes();
Map<const bNode *, TreeZone *> zone_by_inout_node;
Map<const bNode *, bNodeTreeZone *> 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<TreeZones> 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<TreeZones> discover_tree_zones(const bNodeTree &tree)
}
/* Update depths. */
for (std::unique_ptr<TreeZone> &zone : tree_zones->zones) {
for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
update_zone_depths(*zone);
}
for (std::unique_ptr<TreeZone> &zone : tree_zones->zones) {
for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
if (zone->depth == 0) {
tree_zones->root_zones.append(zone.get());
}
@ -262,7 +266,7 @@ static std::unique_ptr<TreeZones> 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<TreeZones> 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);
const bNodeTreeZone *zone = this->get_zone_by_node(node.identifier);
if (zone == nullptr) {
return zone;
}
if (zone->input_node == &node) {
if (socket.is_input()) {
return zone->parent_zone;
}
}
if (zone->output_node == &node) {
if (socket.is_output()) {
return zone->parent_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;
}
const TreeZone &zone = *this->zones[zone_i];
if (zone.input_node == &node) {
if (socket.is_input()) {
return zone.parent_zone;
}
}
if (zone.output_node == &node) {
if (socket.is_output()) {
return zone.parent_zone;
}
}
return &zone;
return this->zones[zone_i].get();
}
} // namespace blender::bke::node_tree_zones
Vector<const bNodeTreeZone *> 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<const bNodeTreeZone *> 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

View File

@ -1424,14 +1424,15 @@ static int ptcache_filepath(PTCacheID *pid,
idname = (pid->owner_id->name + 2);
/* convert chars to hex so they are always a valid filename */
while ('\0' != *idname) {
BLI_snprintf(newname, MAX_PTCACHE_FILE - len, "%02X", (uint)(*idname++));
newname += 2;
len += 2;
/* Always 2 unless there isn't enough room in the string. */
const int temp = BLI_snprintf_rlen(
newname, MAX_PTCACHE_FILE - len, "%02X", (uint)(*idname++));
newname += temp;
len += temp;
}
}
else {
int temp = (int)strlen(pid->cache->name);
strcpy(newname, pid->cache->name);
int temp = BLI_strncpy_rlen(newname, pid->cache->name, MAX_PTCACHE_FILE - len);
newname += temp;
len += temp;
}

View File

@ -462,8 +462,7 @@ bSound *BKE_sound_new_buffer(Main *bmain, bSound *source)
bSound *sound = NULL;
char name[MAX_ID_NAME + 5];
strcpy(name, "buf_");
strcpy(name + 4, source->id.name);
BLI_string_join(name, sizeof(name), "buf_", source->id.name);
sound = BKE_libblock_alloc(bmain, ID_SO, name);
@ -480,8 +479,7 @@ bSound *BKE_sound_new_limiter(Main *bmain, bSound *source, float start, float en
bSound *sound = NULL;
char name[MAX_ID_NAME + 5];
strcpy(name, "lim_");
strcpy(name + 4, source->id.name);
BLI_string_join(name, sizeof(name), "lim_", source->id.name);
sound = BKE_libblock_alloc(bmain, ID_SO, name);

View File

@ -499,7 +499,7 @@ MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBa
const MovieTrackingSettings *settings = &tracking->settings;
MovieTrackingTrack *track = MEM_cnew<MovieTrackingTrack>("add_marker_exec track");
strcpy(track->name, "Track");
STRNCPY(track->name, "Track");
/* Fill track's settings from default settings. */
track->motion_model = settings->default_motion_model;
@ -1579,7 +1579,7 @@ MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
plane_track = MEM_cnew<MovieTrackingPlaneTrack>("new plane track");
/* Use some default name. */
strcpy(plane_track->name, "Plane Track");
STRNCPY(plane_track->name, "Plane Track");
plane_track->image_opacity = 1.0f;

View File

@ -295,7 +295,7 @@ static VFontData *vfont_get_data(VFont *vfont)
/* DON'T DO THIS
* missing file shouldn't modify path! - campbell */
#if 0
strcpy(vfont->filepath, FO_BUILTIN_NAME);
STRNCPY(vfont->filepath, FO_BUILTIN_NAME);
#endif
pf = get_builtin_packedfile();
}

View File

@ -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<NodeViewerPathElem *>(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<GroupNodeViewerPathElem *>(elem);
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *typed_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(elem);
BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *typed_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(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<NodeViewerPathElem *>(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<typename T> static T *make_elem(const ViewerPathElemType type)
{
T *elem = MEM_cnew<T>(__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<IDViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<IDViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<ModifierViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
return &make_elem<GroupNodeViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
return &make_elem<ViewerNodeViewerPathElem>(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<NodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE));
return reinterpret_cast<GroupNodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE));
}
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone()
{
return reinterpret_cast<SimulationZoneViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE));
}
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
{
return reinterpret_cast<ViewerNodeViewerPathElem *>(
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<const IDViewerPathElem *>(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<const NodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<NodeViewerPathElem *>(dst);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *old_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<GroupNodeViewerPathElem *>(dst);
new_elem->node_id = old_elem->node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *old_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(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<const ViewerNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(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<const ModifierViewerPathElem *>(b);
return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name);
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *a_elem = reinterpret_cast<const NodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const NodeViewerPathElem *>(b);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *a_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *a_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(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<const ViewerNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(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<NodeViewerPathElem *>(elem);
MEM_SAFE_FREE(typed_elem->node_name);
break;
}
}
if (elem->ui_name) {
MEM_freeN(elem->ui_name);
}
MEM_freeN(elem);
}

View File

@ -83,7 +83,10 @@ static int append_avi(void *context_v,
int recty,
const char *suffix,
ReportList *reports);
static void filepath_avi(char *string, const RenderData *rd, bool preview, const char *suffix);
static void filepath_avi(char filepath[FILE_MAX],
const RenderData *rd,
bool preview,
const char *suffix);
static void *context_create_avi(void);
static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
@ -141,7 +144,10 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI
static void filepath_avi(char *filepath, const RenderData *rd, bool preview, const char *suffix)
static void filepath_avi(char filepath[FILE_MAX],
const RenderData *rd,
bool preview,
const char *suffix)
{
int sfra, efra;
@ -158,7 +164,7 @@ static void filepath_avi(char *filepath, const RenderData *rd, bool preview, con
efra = rd->efra;
}
strcpy(filepath, rd->pic);
BLI_strncpy(filepath, rd->pic, FILE_MAX);
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
BLI_file_ensure_parent_dir_exists(filepath);
@ -188,13 +194,13 @@ static int start_avi(void *context_v,
const char *suffix)
{
int x, y;
char name[256];
char filepath[FILE_MAX];
AviFormat format;
int quality;
double framerate;
AviMovie *avi = context_v;
filepath_avi(name, rd, preview, suffix);
filepath_avi(filepath, rd, preview, suffix);
x = rectx;
y = recty;
@ -209,7 +215,7 @@ static int start_avi(void *context_v,
format = AVI_FORMAT_MJPEG;
}
if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) {
BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
return 0;
}
@ -222,7 +228,7 @@ static int start_avi(void *context_v,
avi->interlace = 0;
avi->odd_fields = 0;
printf("Created avi: %s\n", name);
printf("Created avi: %s\n", filepath);
return 1;
}
@ -298,7 +304,10 @@ static void context_free_avi(void *context_v)
#endif /* WITH_AVI */
void BKE_movie_filepath_get(char *filepath, const RenderData *rd, bool preview, const char *suffix)
void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const RenderData *rd,
bool preview,
const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh && mh->get_movie_path) {

View File

@ -1428,7 +1428,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
BLI_path_suffix(filepath, FILE_MAX, suffix, "");
}
void BKE_ffmpeg_filepath_get(char *filepath,
void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const RenderData *rd,
bool preview,
const char *suffix)

View File

@ -599,7 +599,8 @@ template<typename T> 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];
}

View File

@ -15,7 +15,7 @@
# include <dirent.h>
#endif
#include <string.h> /* #strcpy etc. */
#include <string.h>
#include <sys/stat.h>
#include <time.h>
@ -320,7 +320,7 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
{
#ifdef WIN32
UNUSED_VARS(st);
strcpy(r_owner, "unknown");
BLI_strncpy(r_owner, "unknown", FILELIST_DIRENTRY_OWNER_LEN);
#else
struct passwd *pwuser = getpwuid(st->st_uid);

View File

@ -117,7 +117,7 @@ int BLI_path_sequence_decode(const char *path,
if (head) {
/* Name_end points to last character of head,
* make it +1 so null-terminator is nicely placed. */
BLI_strncpy(head, path, name_end + 1);
BLI_strncpy(head, path, MIN2(head_maxncpy, name_end + 1));
}
if (r_digits_len) {
*r_digits_len = 0;
@ -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:
@ -793,7 +793,7 @@ void BLI_path_rel(char path[FILE_MAX], const char *basepath)
#ifdef WIN32
BLI_str_replace_char(res + 2, '/', '\\');
#endif
strcpy(path, res);
BLI_strncpy(path, res, FILE_MAX);
}
}

View File

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

View File

@ -1086,9 +1086,8 @@ uint BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float n
for (a = 0; a < poly; a++, pf++) {
for (c = (ushort)(a + 1); c < poly; c++) {
/* if 'a' inside 'c': join (bbox too)
* Careful: 'a' can also be inside another poly.
*/
/* If 'a' inside 'c': join (bounding-box too)
* Careful: 'a' can also be inside another poly. */
if (boundisect(pf, pflist + c)) {
*pc = c;
pc++;

View File

@ -32,7 +32,7 @@
#endif
#include <fcntl.h>
#include <string.h> /* `strcpy` etc. */
#include <string.h>
#ifdef WIN32
# include "BLI_string_utf8.h"
@ -145,16 +145,17 @@ double BLI_dir_free_space(const char *dir)
return -1;
}
strcpy(dirname, dir);
memcpy(dirname, dir, len + 1);
if (len) {
slash = strrchr(dirname, '/');
if (slash) {
slash[1] = 0;
slash[1] = '\0';
}
}
else {
strcpy(dirname, "/");
dirname[0] = '/';
dirname[1] = '\0';
}
# if defined(USE_STATFS_STATVFS)

View File

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

View File

@ -204,6 +204,8 @@ void BLO_blendfiledata_free(BlendFileData *bfd);
typedef struct BLODataBlockInfo {
char name[64]; /* MAX_NAME */
struct AssetMetaData *asset_data;
/** Ownership over #asset_data above can be "stolen out" of this struct, for more permanent
* storage. In that case, set this to false to avoid double freeing of the stolen data. */
bool free_asset_data;
/**
* Optimization: Tag data-blocks for which we know there is no preview.

View File

@ -716,7 +716,7 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
for (ma = bmain->materials.first; ma; ma = ma->id.next) {
if (ma->nodetree && ma->nodetree->id.name[0] == '\0') {
strcpy(ma->nodetree->id.name, "NTShader Nodetree");
STRNCPY(ma->nodetree->id.name, "NTShader Nodetree");
}
}
@ -724,7 +724,7 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (sce = bmain->scenes.first; sce; sce = sce->id.next) {
enum { R_PANORAMA = (1 << 10) };
if (sce->nodetree && sce->nodetree->id.name[0] == '\0') {
strcpy(sce->nodetree->id.name, "NTCompositing Nodetree");
STRNCPY(sce->nodetree->id.name, "NTCompositing Nodetree");
}
/* move to cameras */
@ -748,7 +748,7 @@ void blo_do_versions_250(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (tx->nodetree) {
if (tx->nodetree->id.name[0] == '\0') {
strcpy(tx->nodetree->id.name, "NTTexture Nodetree");
STRNCPY(tx->nodetree->id.name, "NTTexture Nodetree");
}
/* which_output 0 is now "not specified" */
@ -2315,7 +2315,7 @@ static void lib_node_do_versions_group_indices(bNode *gnode)
for (link = ngroup->links.first; link; link = link->next) {
if (link->tonode == NULL && link->fromsock->own_index == old_index) {
strcpy(sock->identifier, link->fromsock->identifier);
STRNCPY(sock->identifier, link->fromsock->identifier);
/* deprecated */
sock->own_index = link->fromsock->own_index;
sock->to_index = 0;
@ -2327,7 +2327,7 @@ static void lib_node_do_versions_group_indices(bNode *gnode)
for (link = ngroup->links.first; link; link = link->next) {
if (link->fromnode == NULL && link->tosock->own_index == old_index) {
strcpy(sock->identifier, link->tosock->identifier);
STRNCPY(sock->identifier, link->tosock->identifier);
/* deprecated */
sock->own_index = link->tosock->own_index;
sock->to_index = 0;

File diff suppressed because it is too large Load Diff

View File

@ -1363,7 +1363,7 @@ static void version_switch_node_input_prefix(Main *bmain)
if (socket == node->inputs.first) {
continue;
}
strcpy(socket->name, socket->name[0] == 'A' ? "False" : "True");
STRNCPY(socket->name, socket->name[0] == 'A' ? "False" : "True");
/* Replace "A" and "B", but keep the unique number suffix at the end. */
char number_suffix[8];
@ -1940,7 +1940,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "FunctionNodeCombineColor");
STRNCPY(node->idname, "FunctionNodeCombineColor");
node->storage = storage;
break;
}
@ -1949,7 +1949,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "FunctionNodeSeparateColor");
STRNCPY(node->idname, "FunctionNodeSeparateColor");
node->storage = storage;
break;
}
@ -2007,7 +2007,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "CompositorNodeCombineColor");
STRNCPY(node->idname, "CompositorNodeCombineColor");
node->storage = storage;
break;
}
@ -2016,7 +2016,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
strcpy(node->idname, "CompositorNodeCombineColor");
STRNCPY(node->idname, "CompositorNodeCombineColor");
node->storage = storage;
break;
}
@ -2026,7 +2026,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
storage->ycc_mode = node->custom1;
strcpy(node->idname, "CompositorNodeCombineColor");
STRNCPY(node->idname, "CompositorNodeCombineColor");
node->storage = storage;
break;
}
@ -2035,7 +2035,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
strcpy(node->idname, "CompositorNodeCombineColor");
STRNCPY(node->idname, "CompositorNodeCombineColor");
node->storage = storage;
break;
}
@ -2044,7 +2044,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "CompositorNodeSeparateColor");
STRNCPY(node->idname, "CompositorNodeSeparateColor");
node->storage = storage;
break;
}
@ -2053,7 +2053,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
strcpy(node->idname, "CompositorNodeSeparateColor");
STRNCPY(node->idname, "CompositorNodeSeparateColor");
node->storage = storage;
break;
}
@ -2063,7 +2063,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
storage->ycc_mode = node->custom1;
strcpy(node->idname, "CompositorNodeSeparateColor");
STRNCPY(node->idname, "CompositorNodeSeparateColor");
node->storage = storage;
break;
}
@ -2072,7 +2072,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
sizeof(NodeCMPCombSepColor), __func__);
storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
strcpy(node->idname, "CompositorNodeSeparateColor");
STRNCPY(node->idname, "CompositorNodeSeparateColor");
node->storage = storage;
break;
}
@ -2087,13 +2087,13 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
case TEX_NODE_COMPOSE_LEGACY: {
node->type = TEX_NODE_COMBINE_COLOR;
node->custom1 = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "TextureNodeCombineColor");
STRNCPY(node->idname, "TextureNodeCombineColor");
break;
}
case TEX_NODE_DECOMPOSE_LEGACY: {
node->type = TEX_NODE_SEPARATE_COLOR;
node->custom1 = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "TextureNodeSeparateColor");
STRNCPY(node->idname, "TextureNodeSeparateColor");
break;
}
}
@ -2127,7 +2127,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "ShaderNodeCombineColor");
STRNCPY(node->idname, "ShaderNodeCombineColor");
node->storage = storage;
break;
}
@ -2136,7 +2136,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_HSV;
strcpy(node->idname, "ShaderNodeCombineColor");
STRNCPY(node->idname, "ShaderNodeCombineColor");
node->storage = storage;
break;
}
@ -2145,7 +2145,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_RGB;
strcpy(node->idname, "ShaderNodeSeparateColor");
STRNCPY(node->idname, "ShaderNodeSeparateColor");
node->storage = storage;
break;
}
@ -2154,7 +2154,7 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre
NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
__func__);
storage->mode = NODE_COMBSEP_COLOR_HSV;
strcpy(node->idname, "ShaderNodeSeparateColor");
STRNCPY(node->idname, "ShaderNodeSeparateColor");
node->storage = storage;
break;
}
@ -2171,7 +2171,7 @@ static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree)
version_node_output_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color", "Result_Color");
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_MIX_RGB_LEGACY) {
strcpy(node->idname, "ShaderNodeMix");
STRNCPY(node->idname, "ShaderNodeMix");
node->type = SH_NODE_MIX;
NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__);
data->blend_type = node->custom1;
@ -2570,7 +2570,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == GEO_NODE_SUBDIVIDE_MESH) {
strcpy(node->idname, "GeometryNodeMeshSubdivide");
STRNCPY(node->idname, "GeometryNodeMeshSubdivide");
}
}
}
@ -3266,7 +3266,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
sizeof(NodeFunctionCompare), __func__);
data->data_type = SOCK_FLOAT;
data->operation = node->custom1;
strcpy(node->idname, "FunctionNodeCompare");
STRNCPY(node->idname, "FunctionNodeCompare");
node->storage = data;
}
}

View File

@ -164,7 +164,7 @@ static void versioning_replace_legacy_glossy_node(bNodeTree *ntree)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_BSDF_GLOSSY_LEGACY) {
strcpy(node->idname, "ShaderNodeBsdfAnisotropic");
STRNCPY(node->idname, "ShaderNodeBsdfAnisotropic");
node->type = SH_NODE_BSDF_GLOSSY;
}
}

View File

@ -191,7 +191,7 @@ void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name
for (bNode *node : ntree->all_nodes()) {
if (node->type == node_type) {
if (!STREQ(node->idname, new_name)) {
strcpy(node->idname, new_name);
STRNCPY(node->idname, new_name);
}
}
}

View File

@ -1040,8 +1040,8 @@ static void update_voronoi_node_fac_output(bNodeTree *ntree)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI) {
bNodeSocket *facOutput = BLI_findlink(&node->outputs, 1);
strcpy(facOutput->identifier, "Distance");
strcpy(facOutput->name, "Distance");
STRNCPY(facOutput->identifier, "Distance");
STRNCPY(facOutput->name, "Distance");
}
}
}

View File

@ -324,7 +324,7 @@ static void customdata_version_242(Mesh *me)
if (layer->type == CD_MTFACE) {
if (layer->name[0] == 0) {
if (mtfacen == 0) {
strcpy(layer->name, "UVMap");
STRNCPY(layer->name, "UVMap");
}
else {
SNPRINTF(layer->name, "UVMap.%.3d", mtfacen);
@ -335,7 +335,7 @@ static void customdata_version_242(Mesh *me)
else if (layer->type == CD_MCOL) {
if (layer->name[0] == 0) {
if (mcoln == 0) {
strcpy(layer->name, "Col");
STRNCPY(layer->name, "Col");
}
else {
SNPRINTF(layer->name, "Col.%.3d", mcoln);
@ -843,7 +843,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
VFont *vf;
for (vf = bmain->fonts.first; vf; vf = vf->id.next) {
if (BLI_str_endswith(vf->filepath, ".Bfont")) {
strcpy(vf->filepath, FO_BUILTIN_NAME);
STRNCPY(vf->filepath, FO_BUILTIN_NAME);
}
}
}
@ -1476,7 +1476,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (kb = key->block.first; kb; kb = kb->next) {
if (kb == key->refkey) {
if (kb->name[0] == 0) {
strcpy(kb->name, "Basis");
STRNCPY(kb->name, "Basis");
}
}
else {
@ -1611,8 +1611,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
Image *ima;
for (ima = bmain->images.first; ima; ima = ima->id.next) {
if (STREQ(ima->filepath, "Compositor")) {
strcpy(ima->id.name + 2, "Viewer Node");
strcpy(ima->filepath, "Viewer Node");
BLI_strncpy(ima->id.name + 2, "Viewer Node", sizeof(ima->id.name) - 2);
STRNCPY(ima->filepath, "Viewer Node");
}
}
}

View File

@ -237,7 +237,7 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(192, 0)) {
strcpy(userdef->sounddir, "/");
STRNCPY(userdef->sounddir, "/");
}
/* patch to set Dupli Armature */
@ -311,52 +311,52 @@ void blo_do_versions_userdef(UserDef *userdef)
for (km = userdef->user_keymaps.first; km; km = km->next) {
if (STREQ(km->idname, "Armature_Sketch")) {
strcpy(km->idname, "Armature Sketch");
STRNCPY(km->idname, "Armature Sketch");
}
else if (STREQ(km->idname, "View3D")) {
strcpy(km->idname, "3D View");
STRNCPY(km->idname, "3D View");
}
else if (STREQ(km->idname, "View3D Generic")) {
strcpy(km->idname, "3D View Generic");
STRNCPY(km->idname, "3D View Generic");
}
else if (STREQ(km->idname, "EditMesh")) {
strcpy(km->idname, "Mesh");
STRNCPY(km->idname, "Mesh");
}
else if (STREQ(km->idname, "UVEdit")) {
strcpy(km->idname, "UV Editor");
STRNCPY(km->idname, "UV Editor");
}
else if (STREQ(km->idname, "Animation_Channels")) {
strcpy(km->idname, "Animation Channels");
STRNCPY(km->idname, "Animation Channels");
}
else if (STREQ(km->idname, "GraphEdit Keys")) {
strcpy(km->idname, "Graph Editor");
STRNCPY(km->idname, "Graph Editor");
}
else if (STREQ(km->idname, "GraphEdit Generic")) {
strcpy(km->idname, "Graph Editor Generic");
STRNCPY(km->idname, "Graph Editor Generic");
}
else if (STREQ(km->idname, "Action_Keys")) {
strcpy(km->idname, "Dopesheet");
STRNCPY(km->idname, "Dopesheet");
}
else if (STREQ(km->idname, "NLA Data")) {
strcpy(km->idname, "NLA Editor");
STRNCPY(km->idname, "NLA Editor");
}
else if (STREQ(km->idname, "Node Generic")) {
strcpy(km->idname, "Node Editor");
STRNCPY(km->idname, "Node Editor");
}
else if (STREQ(km->idname, "Logic Generic")) {
strcpy(km->idname, "Logic Editor");
STRNCPY(km->idname, "Logic Editor");
}
else if (STREQ(km->idname, "File")) {
strcpy(km->idname, "File Browser");
STRNCPY(km->idname, "File Browser");
}
else if (STREQ(km->idname, "FileMain")) {
strcpy(km->idname, "File Browser Main");
STRNCPY(km->idname, "File Browser Main");
}
else if (STREQ(km->idname, "FileButtons")) {
strcpy(km->idname, "File Browser Buttons");
STRNCPY(km->idname, "File Browser Buttons");
}
else if (STREQ(km->idname, "Buttons Generic")) {
strcpy(km->idname, "Property Editor");
STRNCPY(km->idname, "Property Editor");
}
}
}

View File

@ -54,8 +54,8 @@
* - write #BLO_CODE_GLOB (#FileGlobal struct) (some global vars).
* - write #BLO_CODE_DNA1 (#SDNA struct)
* - write #BLO_CODE_USER (#UserDef struct) for file paths:
- #BLENDER_STARTUP_FILE (on UNIX `~/.config/blender/X.X/config/startup.blend`).
- #BLENDER_USERPREF_FILE (on UNIX `~/.config/blender/X.X/config/userpref.blend`).
* - #BLENDER_STARTUP_FILE (on UNIX `~/.config/blender/X.X/config/startup.blend`).
* - #BLENDER_USERPREF_FILE (on UNIX `~/.config/blender/X.X/config/userpref.blend`).
*/
#include <cerrno>

View File

@ -440,7 +440,7 @@ BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
{
BMLoop *l_other;
// BLI_assert(BM_edge_is_manifold(e)); // TOO strict, just check if we have another radial face
// BLI_assert(BM_edge_is_manifold(e)); /* Too strict, just check there is another radial face. */
BLI_assert(e->l && e->l->radial_next != e->l);
BLI_assert(BM_vert_in_edge(e, l->v));

View File

@ -112,6 +112,7 @@ set(GLSL_SRC
shaders/compositor_blur_variable_size.glsl
shaders/compositor_bokeh_image.glsl
shaders/compositor_box_mask.glsl
shaders/compositor_compute_preview.glsl
shaders/compositor_convert.glsl
shaders/compositor_despeckle.glsl
shaders/compositor_directional_blur.glsl
@ -226,6 +227,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_blur_variable_size_info.hh
shaders/infos/compositor_bokeh_image_info.hh
shaders/infos/compositor_box_mask_info.hh
shaders/infos/compositor_compute_preview_info.hh
shaders/infos/compositor_convert_info.hh
shaders/infos/compositor_despeckle_info.hh
shaders/infos/compositor_directional_blur_info.hh

View File

@ -42,6 +42,9 @@ class Context {
public:
Context(TexturePool &texture_pool);
/* Get the compositing scene. */
virtual const Scene &get_scene() const = 0;
/* Get the node tree used for compositing. */
virtual const bNodeTree &get_node_tree() const = 0;

View File

@ -12,6 +12,7 @@
#include "COM_context.hh"
#include "COM_operation.hh"
#include "COM_result.hh"
#include "COM_scheduler.hh"
namespace blender::realtime_compositor {
@ -44,6 +45,12 @@ class NodeOperation : public Operation {
void compute_results_reference_counts(const Schedule &schedule);
protected:
/* Compute a preview for the operation and set to the bNodePreview of the node. This is only done
* for nodes which enables previews, are not hidden, and are part of the active node context. The
* preview is computed as a lower resolution version of the output of the get_preview_result
* method. */
void compute_preview() override;
/* Returns a reference to the derived node that this operation represents. */
const DNode &node() const;
@ -53,6 +60,17 @@ class NodeOperation : public Operation {
/* Returns true if the output identified by the given identifier is needed and should be
* computed, otherwise returns false. */
bool should_compute_output(StringRef identifier);
private:
/* Get the result which will be previewed in the node, this is chosen as the first linked output
* of the node, if no outputs exist, then the first allocated input will be chosen. Nullptr is
* guaranteed not to be returned, since the node will always either have a linked output or an
* allocated input. */
Result *get_preview_result();
/* Resize the give input result to the given preview size and set it to the preview buffer after
* applying the necessary color management processor.*/
void write_preview_from_result(bNodePreview &preview, Result &input_result);
};
} // namespace blender::realtime_compositor

View File

@ -130,6 +130,10 @@ class Operation {
* output results. */
virtual void execute() = 0;
/* Compute and set a preview of the operation if needed. This method defaults to an empty
* implementation and should be implemented by operations which can have previews. */
virtual void compute_preview();
/* Get a reference to the result connected to the input identified by the given identifier. */
Result &get_input(StringRef identifier) const;

View File

@ -4,15 +4,29 @@
#include <memory>
#include "BLI_assert.h"
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_math_base.hh"
#include "BLI_math_color.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "IMB_colormanagement.h"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_node_declaration.hh"
#include "BKE_node.h"
#include "COM_context.hh"
#include "COM_input_descriptor.hh"
#include "COM_node_operation.hh"
@ -39,6 +53,126 @@ NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context),
}
}
/* Given the size of a result, compute a lower resolution size for a preview. The greater dimension
* will be assigned an arbitrarily chosen size of 128, while the other dimension will get the size
* that maintains the same aspect ratio. */
static int2 compute_preview_size(int2 size)
{
const int greater_dimension_size = 128;
if (size.x > size.y) {
return int2(greater_dimension_size, int(greater_dimension_size * (float(size.y) / size.x)));
}
else {
return int2(int(greater_dimension_size * (float(size.x) / size.y)), greater_dimension_size);
}
}
void NodeOperation::compute_preview()
{
if (!(node()->flag & NODE_PREVIEW)) {
return;
}
if (node()->flag & NODE_HIDDEN) {
return;
}
/* Only compute previews for nodes in the active context. */
if (node().context()->instance_key().value !=
node().context()->derived_tree().active_context().instance_key().value)
{
return;
}
/* Initialize node tree previews if not already initialized. */
bNodeTree *root_tree = const_cast<bNodeTree *>(
&node().context()->derived_tree().root_context().btree());
if (!root_tree->previews) {
root_tree->previews = BKE_node_instance_hash_new("node previews");
}
Result *preview_result = get_preview_result();
const int2 preview_size = compute_preview_size(preview_result->domain().size);
node()->runtime->preview_xsize = preview_size.x;
node()->runtime->preview_ysize = preview_size.y;
bNodePreview *preview = bke::node_preview_verify(
root_tree->previews, node().instance_key(), preview_size.x, preview_size.y, true);
write_preview_from_result(*preview, *preview_result);
}
Result *NodeOperation::get_preview_result()
{
/* Find the first linked output. */
for (const bNodeSocket *output : node()->output_sockets()) {
Result &output_result = get_result(output->identifier);
if (output_result.should_compute()) {
return &output_result;
}
}
/* No linked outputs, find the first allocated input. */
for (const bNodeSocket *input : node()->input_sockets()) {
Result &input_result = get_input(input->identifier);
if (input_result.is_allocated()) {
return &input_result;
}
}
BLI_assert_unreachable();
return nullptr;
}
void NodeOperation::write_preview_from_result(bNodePreview &preview, Result &input_result)
{
GPUShader *shader = shader_manager().get("compositor_compute_preview");
GPU_shader_bind(shader);
if (input_result.type() == ResultType::Float) {
GPU_texture_swizzle_set(input_result.texture(), "rrr1");
}
input_result.bind_as_texture(shader, "input_tx");
const int2 preview_size = int2(preview.xsize, preview.ysize);
Result preview_result = Result::Temporary(ResultType::Color, texture_pool());
preview_result.allocate_texture(Domain(preview_size));
preview_result.bind_as_image(shader, "preview_img");
compute_dispatch_threads_at_least(shader, preview_size);
input_result.unbind_as_texture();
preview_result.unbind_as_image();
GPU_shader_unbind();
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
float *preview_pixels = static_cast<float *>(
GPU_texture_read(preview_result.texture(), GPU_DATA_FLOAT, 0));
preview_result.release();
ColormanageProcessor *color_processor = IMB_colormanagement_display_processor_new(
&context().get_scene().view_settings, &context().get_scene().display_settings);
threading::parallel_for(IndexRange(preview_size.y), 1, [&](const IndexRange sub_y_range) {
for (const int64_t y : sub_y_range) {
for (const int64_t x : IndexRange(preview_size.x)) {
const int index = (y * preview_size.x + x) * 4;
IMB_colormanagement_processor_apply_v4(color_processor, preview_pixels + index);
rgba_float_to_uchar(preview.rect + index, preview_pixels + index);
}
}
});
/* Restore original swizzle mask set above. */
if (input_result.type() == ResultType::Float) {
GPU_texture_swizzle_set(input_result.texture(), "rgba");
}
IMB_colormanagement_processor_free(color_processor);
MEM_freeN(preview_pixels);
}
void NodeOperation::compute_results_reference_counts(const Schedule &schedule)
{
for (const bNodeSocket *output : this->node()->output_sockets()) {

View File

@ -35,6 +35,8 @@ void Operation::evaluate()
execute();
compute_preview();
release_inputs();
release_unneeded_results();
@ -136,6 +138,8 @@ void Operation::add_and_evaluate_input_processor(StringRef identifier, SimpleOpe
processor->evaluate();
}
void Operation::compute_preview(){};
Result &Operation::get_input(StringRef identifier) const
{
return *results_mapped_to_inputs_.lookup(identifier);

View File

@ -21,58 +21,6 @@ namespace blender::realtime_compositor {
using namespace nodes::derived_node_tree_types;
/* Find the active context from the given context and its descendants contexts. The active context
* is the one whose node instance key matches the active_viewer_key stored in the root node tree.
* The instance key of each context is computed by calling BKE_node_instance_key given the key of
* the parent as well as the group node making the context. */
static const DTreeContext *find_active_context_recursive(const DTreeContext *context,
bNodeInstanceKey key)
{
/* The instance key of the given context matches the active viewer instance key, so this is the
* active context, return it. */
if (key.value == context->derived_tree().root_context().btree().active_viewer_key.value) {
return context;
}
/* For each of the group nodes, compute their instance key and contexts and call this function
* recursively. */
for (const bNode *group_node : context->btree().group_nodes()) {
const bNodeInstanceKey child_key = BKE_node_instance_key(key, &context->btree(), group_node);
const DTreeContext *child_context = context->child_context(*group_node);
const DTreeContext *found_context = find_active_context_recursive(child_context, child_key);
/* If the found context is null, that means neither the child context nor one of its descendant
* contexts is active. */
if (!found_context) {
continue;
}
/* Otherwise, we have found our active context, return it. */
return found_context;
}
/* Neither the given context nor one of its descendant contexts is active, so return null. */
return nullptr;
}
/* Find the active context for the given node tree. The active context represents the node tree
* currently being edited. In most cases, that would be the top level node tree itself, but in the
* case where the user is editing the node tree of a node group, the active context would be a
* representation of the node tree of that node group. Note that the context also stores the group
* node that the user selected to edit the node tree, so the context fully represents a particular
* instance of the node group. */
static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
{
/* If the active viewer key is NODE_INSTANCE_KEY_NONE, that means it is not yet initialized and
* we return the root context in that case. See the find_active_context_recursive function. */
if (tree.root_context().btree().active_viewer_key.value == NODE_INSTANCE_KEY_NONE.value) {
return &tree.root_context();
}
/* The root context has an instance key of NODE_INSTANCE_KEY_BASE by definition. */
return find_active_context_recursive(&tree.root_context(), NODE_INSTANCE_KEY_BASE);
}
/* Add the viewer node which is marked as NODE_DO_OUTPUT in the given context to the given stack.
* If multiple types of viewer nodes are marked, then the preference will be CMP_NODE_VIEWER >
* CMP_NODE_SPLITVIEWER. If no viewer nodes were found, composite nodes can be added as a fallback
@ -114,7 +62,8 @@ static bool add_viewer_nodes_in_context(const DTreeContext *context, Stack<DNode
* Output, Composite, and Viewer nodes. Viewer nodes are a special case, as only the nodes that
* satisfies the requirements in the add_viewer_nodes_in_context function are added. First, the
* active context is searched for viewer nodes, if non were found, the root context is searched.
* For more information on what contexts mean here, see the find_active_context function. */
* For more information on what contexts mean here, see the DerivedNodeTree::active_context()
* function. */
static void add_output_nodes(const Context &context,
const DerivedNodeTree &tree,
Stack<DNode> &node_stack)
@ -139,8 +88,8 @@ static void add_output_nodes(const Context &context,
}
}
const DTreeContext *active_context = find_active_context(tree);
const bool viewer_was_added = add_viewer_nodes_in_context(active_context, node_stack);
const DTreeContext &active_context = tree.active_context();
const bool viewer_was_added = add_viewer_nodes_in_context(&active_context, node_stack);
/* An active viewer was added, no need to search further. */
if (viewer_was_added) {
@ -149,7 +98,7 @@ static void add_output_nodes(const Context &context,
/* If the active context is the root one and no viewer nodes were found, we consider this node
* tree to have no viewer nodes, even if one of the non-active descendants have viewer nodes. */
if (active_context->is_root()) {
if (active_context.is_root()) {
return;
}
@ -394,7 +343,8 @@ Schedule compute_schedule(const Context &context, const DerivedNodeTree &tree)
int insertion_position = 0;
for (int i = 0; i < sorted_dependency_nodes.size(); i++) {
if (needed_buffers.lookup(doutput.node()) >
needed_buffers.lookup(sorted_dependency_nodes[i])) {
needed_buffers.lookup(sorted_dependency_nodes[i]))
{
insertion_position++;
}
else {

View File

@ -0,0 +1,6 @@
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(imageSize(preview_img));
imageStore(preview_img, texel, texture(input_tx, coordinates));
}

View File

@ -0,0 +1,12 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_compute_preview)
.local_group_size(16, 16)
.sampler(0, ImageType::FLOAT_2D, "input_tx")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img")
.compute_source("compositor_compute_preview.glsl")
.do_static_compilation(true);

View File

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

View File

@ -34,7 +34,7 @@ void ObjectRuntimeBackup::init_from_object(Object *object)
light_linking_runtime = object->light_linking->runtime;
}
BKE_object_runtime_reset(object);
/* Keep bbox (for now at least). */
/* Keep bounding-box (for now at least). */
object->runtime.bb = runtime.bb;
/* Object update will override actual object->data to an evaluated version.
* Need to make sure we don't have data set to evaluated one before free

View File

@ -58,6 +58,11 @@ class Context : public realtime_compositor::Context {
{
}
const Scene &get_scene() const override
{
return *DRW_context_state_get()->scene;
}
const bNodeTree &get_node_tree() const override
{
return *DRW_context_state_get()->scene->nodetree;

View File

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

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