From 9957096f35fcb9d63ae611464667638dcbfb6dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 9 Mar 2021 11:24:16 +0100 Subject: EEVEE: ScreenSpaceReflections: Improve hit quality This changes the hitBuffer to store `ReflectionDir * HitTime, invPdf` just as the reference presentation. This avoids issues when the hit refinement produce a coordinate that does not land on the correct surface. We now store the pdf in the same texture and store it inversed so we can remove some ALU from the resolve shader. This also rewrite the resolve shader to not be vectorized to improve readability and scalability. --- source/blender/draw/engines/eevee/eevee_effects.c | 2 - .../blender/draw/engines/eevee/eevee_materials.c | 3 +- source/blender/draw/engines/eevee/eevee_private.h | 5 +- .../draw/engines/eevee/eevee_renderpasses.c | 2 +- .../draw/engines/eevee/eevee_screen_raytrace.c | 29 +- .../engines/eevee/shaders/common_uniforms_lib.glsl | 2 + .../engines/eevee/shaders/effect_ssr_frag.glsl | 514 +++++++-------------- .../draw/engines/eevee/shaders/raytrace_lib.glsl | 7 - .../draw/engines/eevee/shaders/ssr_lib.glsl | 8 +- .../draw/engines/eevee/shaders/surface_lib.glsl | 7 - 10 files changed, 190 insertions(+), 389 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index d1d7c67d16c..f4f7acb8862 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -149,8 +149,6 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, */ common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0]; common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1]; - common_data->hiz_uv_scale[2] = 1.0f / effects->hiz_size[0]; - common_data->hiz_uv_scale[3] = 1.0f / effects->hiz_size[1]; /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */ sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0]; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index bc7db4b5df6..042fa621117 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -128,7 +128,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, DRW_shgroup_uniform_float_copy( shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0); if (use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->filtered_radiance); + DRW_shgroup_uniform_texture_ref( + shgrp, "refractColorBuffer", &vedata->txl->filtered_radiance); } } if (use_alpha_blend) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 45afee31591..eb1c51f49dd 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -737,7 +737,6 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *ssr_normal_input; /* Textures from pool */ struct GPUTexture *ssr_specrough_input; struct GPUTexture *ssr_hit_output; - struct GPUTexture *ssr_pdf_output; /* Temporal Anti Aliasing */ int taa_reproject_sample; int taa_current_sample; @@ -854,8 +853,8 @@ typedef struct EEVEE_EffectsInfo { * - Arrays of vec2/vec3 are padded as arrays of vec4. * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ typedef struct EEVEE_CommonUniformBuffer { - float prev_persmat[4][4]; /* mat4 */ - float hiz_uv_scale[4]; /* vec4 */ + float prev_persmat[4][4]; /* mat4 */ + float hiz_uv_scale[2], ssr_uv_scale[2]; /* vec4 */ /* Ambient Occlusion */ /* -- 16 byte aligned -- */ float ao_dist, pad1, ao_factor, pad2; /* vec4 */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 0e16037f42d..5739024993e 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -490,7 +490,7 @@ void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata) tx = txl->maxzbuffer; break; case 2: - tx = effects->ssr_pdf_output; + /* UNUSED */ break; case 3: tx = effects->ssr_normal_input; diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 80a1c9fcbe5..00004b28ef3 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -77,6 +77,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ssr_firefly_fac = FLT_MAX; } + void *owner = (void *)EEVEE_screen_raytrace_init; const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; const int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]}; @@ -86,22 +87,22 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) tracing_res[0] = max_ii(1, tracing_res[0]); tracing_res[1] = max_ii(1, tracing_res[1]); + common_data->ssr_uv_scale[0] = size_fs[0] / ((float)tracing_res[0] * divisor); + common_data->ssr_uv_scale[1] = size_fs[1] / ((float)tracing_res[1] * divisor); + /* MRT for the shading pass in order to output needed data for the SSR pass. */ - effects->ssr_specrough_input = DRW_texture_pool_query_2d( - size_fs[0], size_fs[1], format, &draw_engine_eevee_type); + effects->ssr_specrough_input = DRW_texture_pool_query_2d(UNPACK2(size_fs), format, owner); GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0); /* Ray-tracing output. */ - effects->ssr_hit_output = DRW_texture_pool_query_2d( - tracing_res[0], tracing_res[1], GPU_RG16I, &draw_engine_eevee_type); - effects->ssr_pdf_output = DRW_texture_pool_query_2d( - tracing_res[0], tracing_res[1], GPU_R16F, &draw_engine_eevee_type); + effects->ssr_hit_output = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_RGBA16F, owner); GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), - GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)}); + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), + }); return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); @@ -111,7 +112,6 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); effects->ssr_specrough_input = NULL; effects->ssr_hit_output = NULL; - effects->ssr_pdf_output = NULL; return 0; } @@ -148,7 +148,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v */ DRW_PASS_CREATE(psl->ssr_raytrace, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); @@ -164,17 +163,17 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v } DRW_shgroup_call(grp, quad, NULL); + eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT; + DRW_PASS_CREATE(psl->ssr_resolve, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD); grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); - DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); - DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); - DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->filtered_radiance); + DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->filtered_radiance); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl index 24de4520207..b3174afc799 100644 --- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -69,3 +69,5 @@ layout(std140) uniform common_block #define ssrQuality ssrParameters.x #define ssrThickness ssrParameters.y #define ssrPixelSize ssrParameters.zw + +#define ssrUvScale hizUvScale.zw diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index 66183e1bc02..a9139b7a146 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -6,32 +6,55 @@ #pragma BLENDER_REQUIRE(closure_eval_lib.glsl) #pragma BLENDER_REQUIRE(raytrace_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) -#pragma BLENDER_REQUIRE(ssr_lib.glsl) - -/* Based on Stochastic Screen Space Reflections - * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */ - -#define MAX_MIP 9.0 +#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) +#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(surface_lib.glsl) + +/* Based on: + * "Stochastic Screen Space Reflections" + * by Tomasz Stachowiak. + * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections + * and + * "Stochastic all the things: raytracing in hybrid real-time rendering" + * by Tomasz Stachowiak. + * https://media.contentapi.ea.com/content/dam/ea/seed/presentations/dd18-seed-raytracing-in-hybrid-real-time-rendering.pdf + */ uniform ivec2 halfresOffset; -ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar) +struct HitData { + /** Hit direction scaled by intersection time. */ + vec3 hit_dir; + /** Inverse probability of ray spawning in this direction. */ + float ray_pdf_inv; + /** True if ray has hit valid geometry. */ + bool is_hit; + /** True if ray was generated from a planar reflection probe. */ + bool is_planar; +}; + +vec4 encode_hit_data(HitData data) { - ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */ - hit_data.x *= (is_planar) ? -1 : 1; - hit_data.y *= (has_hit) ? 1 : -1; - return hit_data; + vec4 encoded_data; + encoded_data.xyz = data.hit_dir; + /* Encode planar in Z sign. */ + /* TODO fixme */ + // encoded_data.z = data.is_planar ? -encoded_data.z : encoded_data.z; + /* Record 1.0 / pdf to reduce the computation in the resolve phase. */ + /* Encode hit validity in sign. */ + encoded_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0); + return encoded_data; } -vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) +HitData decode_hit_data(vec4 encoded_data) { - is_planar = (hit_data.x < 0); - has_hit = (hit_data.y > 0); - vec2 hit_co = vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */ - if (is_planar) { - hit_co.x = 1.0 - hit_co.x; - } - return hit_co; + HitData data; + data.hit_dir.xyz = encoded_data.xyz; + /* TODO fixme */ + data.is_planar = false; + data.ray_pdf_inv = abs(encoded_data.w); + data.is_hit = (encoded_data.w > 0.0); + return data; } #ifdef STEP_RAYTRACE @@ -39,30 +62,29 @@ vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -layout(location = 0) out ivec2 hitData; -layout(location = 1) out float pdfData; +layout(location = 0) out vec4 hitData; void do_planar_ssr( - int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 vP, float a2, vec4 rand) + int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPlaneNormal, vec3 vP, float a2, vec4 rand) { float NH; - vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); - R = reflect(R, planeNormal); + R = reflect(R, viewPlaneNormal); /* If ray is bad (i.e. going below the plane) regenerate. */ - if (dot(R, planeNormal) > 0.0) { - vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + if (dot(R, viewPlaneNormal) > 0.0) { + /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); pdf = pdf_ggx_reflect(NH, a2); R = reflect(-V, H); - R = reflect(R, planeNormal); + R = reflect(R, viewPlaneNormal); } - pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - Ray ray; ray.origin = vP; ray.direction = R * 1e16; @@ -72,10 +94,14 @@ void do_planar_ssr( params.trace_quality = ssrQuality; params.roughness = a2; - vec3 hit_pos; - bool hit = raytrace_planar(ray, params, index, hit_pos); + HitData data; + data.is_planar = true; + data.ray_pdf_inv = safe_rcp(pdf); + data.is_hit = raytrace_planar(ray, params, index, data.hit_dir); + data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); + data.hit_dir -= ray.origin; - hitData = encode_hit_data(hit_pos.xy, hit, true); + hitData = encode_hit_data(data); } void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) @@ -85,32 +111,6 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); vec3 R = reflect(-V, H); - const float bad_ray_threshold = 0.01; - - vec3 vNg = safe_normalize(cross(dFdx(vP), dFdy(vP))); - - /* If ray is bad (i.e. going below the surface) regenerate. */ - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, 1.0, -1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, -1.0, 1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - /* Not worth tracing. */ - return; - } - - pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ - - vP = raytrace_offset(vP, vNg); - Ray ray; ray.origin = vP; ray.direction = R * 1e16; @@ -121,10 +121,14 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) params.trace_quality = ssrQuality; params.roughness = a2; - vec3 hit_pos; - bool hit = raytrace(ray, params, true, hit_pos); + HitData data; + data.is_planar = true; + data.ray_pdf_inv = safe_rcp(pdf_ggx_reflect(NH, a2)); + data.is_hit = raytrace(ray, params, true, data.hit_dir); + data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); + data.hit_dir -= ray.origin; - hitData = encode_hit_data(hit_pos.xy, hit, false); + hitData = encode_hit_data(data); } in vec4 uvcoordsvar; @@ -132,11 +136,16 @@ in vec4 uvcoordsvar; void main() { vec2 uvs = uvcoordsvar.xy; - float depth = textureLod(depthBuffer, uvs, 0.0).r; + float depth = textureLod(maxzBuffer, uvs * hizUvScale.xy, 0.0).r; + + HitData data; + data.is_planar = false; + data.ray_pdf_inv = safe_rcp(0.0); + data.is_hit = false; + data.hit_dir = vec3(0.0, 0.0, 0.0); /* Default: not hits. */ - hitData = encode_hit_data(vec2(0.5), false, false); - pdfData = 0.0; + hitData = encode_hit_data(data); /* Early out */ /* We can't do discard because we don't clear the render target. */ @@ -193,9 +202,9 @@ void main() /* TODO optimize, use view space for all. */ vec3 tracePosition = line_plane_intersect(P, V, pd.pl_plane_eq); tracePosition = transform_point(ViewMatrix, tracePosition); - vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); + vec3 viewPlaneNormal = transform_direction(ViewMatrix, pd.pl_normal); - do_planar_ssr(i, vV, vN, vT, vB, planeNormal, tracePosition, a2, rand); + do_planar_ssr(i, vV, vN, vT, vB, viewPlaneNormal, tracePosition, a2, rand); return; } } @@ -205,270 +214,92 @@ void main() #else /* STEP_RESOLVE */ -uniform sampler2D prevColorBuffer; /* previous frame */ +uniform sampler2D colorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; - -uniform isampler2D hitBuffer; -uniform sampler2D pdfBuffer; - -uniform int neighborOffset; +uniform sampler2D hitBuffer; in vec4 uvcoordsvar; -const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0), - ivec2(1, 1), - ivec2(-2, 0), - ivec2(0, -2), - ivec2(0, 0), - ivec2(1, -1), - ivec2(-2, 0), - ivec2(0, 2), - ivec2(0, 0), - ivec2(-1, -1), - ivec2(2, 0), - ivec2(0, 2), - ivec2(0, 0), - ivec2(-1, 1), - ivec2(2, 0), - ivec2(0, -2), - - ivec2(0, 0), - ivec2(2, 2), - ivec2(-2, 2), - ivec2(0, -1), - ivec2(0, 0), - ivec2(2, -2), - ivec2(-2, -2), - ivec2(0, 1), - ivec2(0, 0), - ivec2(-2, -2), - ivec2(-2, 2), - ivec2(1, 0), - ivec2(0, 0), - ivec2(2, 2), - ivec2(2, -2), - ivec2(-1, 0)); - out vec4 fragColor; -# if 0 /* Finish reprojection with motion vectors */ -vec3 get_motion_vector(vec3 pos) -{ -} - -/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */ -vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N) -{ - float d_cam = point_plane_projection_dist(cam, pos, N); - float d_hit = point_plane_projection_dist(hit, pos, N); - - if (d_hit < d_cam) { - /* Swap */ - float tmp = d_cam; - d_cam = d_hit; - d_hit = tmp; - } - - vec3 proj_cam = cam - (N * d_cam); - vec3 proj_hit = hit - (N * d_hit); - - return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam; -} -# endif - float brightness(vec3 c) { return max(max(c.r, c.g), c.b); } -vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) +vec4 ssr_get_scene_color_and_mask(vec3 hit_vP, int planar_index, float mip) { - /* TODO real reprojection with motion vectors, etc... */ - return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5; -} - -float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) -{ - if (is_planar) { - hit_co.x = 1.0 - hit_co.x; - return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r; + vec2 uv; + if (planar_index != -1) { + uv = get_uvs_from_view(hit_vP); + /* Planar X axis is flipped. */ + uv.x = 1.0 - uv.x; } else { - return textureLod(depthBuffer, hit_co, 0.0).r; + /* Find hit position in previous frame. */ + /* TODO Combine matrices. */ + vec3 hit_P = transform_point(ViewMatrixInverse, hit_vP); + /* TODO real reprojection with motion vectors, etc... */ + uv = project_point(pastViewProjectionMatrix, hit_P).xy * 0.5 + 0.5; } -} -vec3 get_hit_vector(vec3 hit_pos, - PlanarData pd, - vec3 P, - vec3 N, - vec3 V, - bool is_planar, - inout vec2 hit_co, - inout float mask) -{ - vec3 hit_vec; - - if (is_planar) { - /* Reflect back the hit position to have it in non-reflected world space */ - vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq); - hit_vec = hit_pos - trace_pos; - hit_vec = reflect(hit_vec, pd.pl_normal); - /* Modify here so mip texel alignment is correct. */ - hit_co.x = 1.0 - hit_co.x; + vec3 color; + if (planar_index != -1) { + color = textureLod(probePlanars, vec3(uv, planar_index), mip).rgb; } else { - /* Find hit position in previous frame. */ - hit_co = get_reprojected_reflection(hit_pos, P, N); - hit_vec = hit_pos - P; + color = textureLod(colorBuffer, uv * hizUvScale.xy, mip).rgb; } - mask = screen_border_mask(hit_co); - return hit_vec; -} + /* Clamped brightness. */ + float luma = brightness(color); + color *= 1.0 - max(0.0, luma - ssrFireflyFac) * safe_rcp(luma); -vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) -{ - if (is_planar) { - return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; - } - else { - return textureLod(prevColorBuffer, ref_uvs * hizUvScale.xy, mip).rgb; - } + float mask = screen_border_mask(uv); + return vec4(color, mask); } -vec4 get_ssr_samples(vec4 hit_pdf, - ivec4 hit_data[2], - PlanarData pd, - float planar_index, - vec3 P, - vec3 N, - vec3 V, - float roughnessSquared, - float cone_tan, - vec2 source_uvs, - inout float weight_acc) +void resolve_reflection_sample(int planar_index, + vec2 sample_uv, + vec3 vP, + vec3 vN, + vec3 vV, + float roughness_squared, + float cone_tan, + inout float weight_accum, + inout vec4 ssr_accum) { - bvec4 is_planar, has_hit; - vec4 hit_co[2]; - hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x); - hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y); - hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); - hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); - - /* TODO/FIXME(fclem) This is giving precision issues due to refined intersection. This is most - * noticeable on rough surfaces. */ - vec4 hit_depth; - hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); - hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); - hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index); - hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index); - - /* Hit position in view space. */ - vec3 hit_view[4]; - hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x); - hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y); - hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z); - hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w); - - vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z); - homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3]; - - /* Hit position in world space. */ - vec3 hit_pos[4]; - hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]); - hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]); - hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]); - hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]); - - /* Get actual hit vector and hit coordinate (from last frame). */ - vec4 mask = vec4(1.0); - hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x); - hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y); - hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z); - hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w); - - vec4 hit_dist; - hit_dist.x = length(hit_pos[0]); - hit_dist.y = length(hit_pos[1]); - hit_dist.z = length(hit_pos[2]); - hit_dist.w = length(hit_pos[3]); - hit_dist = max(vec4(1e-8), hit_dist); - - /* Normalize */ - hit_pos[0] /= hit_dist.x; - hit_pos[1] /= hit_dist.y; - hit_pos[2] /= hit_dist.z; - hit_pos[3] /= hit_dist.w; + HitData data = decode_hit_data(texture(hitBuffer, sample_uv * ssrUvScale)); - /* Compute cone footprint in screen space. */ - vec4 cone_footprint = hit_dist * cone_tan; - cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * - max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + float hit_dist = length(data.hit_dir); - /* Estimate a cone footprint to sample a corresponding mipmap level. */ - vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); - mip = clamp(mip, 0.0, MAX_MIP); + /* Slide 54. */ + float bsdf = bsdf_ggx(vN, data.hit_dir / hit_dist, vV, roughness_squared); - /* Slide 54 */ - vec4 bsdf; - bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); - bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared); - bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared); - bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared); + float weight = bsdf * data.ray_pdf_inv; - vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf); + /* Do not add light if ray has failed but still weight it. */ + if (!data.is_hit || (planar_index == -1 && data.is_planar) || + (planar_index != -1 && !data.is_planar)) { + weight_accum += weight; + return; + } - vec3 sample[4]; - sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x); - sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y); - sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z); - sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w); + vec3 hit_vP = vP + data.hit_dir; - /* Clamped brightness. */ - vec4 luma; - luma.x = brightness(sample[0]); - luma.y = brightness(sample[1]); - luma.z = brightness(sample[2]); - luma.w = brightness(sample[3]); - luma = max(vec4(1e-8), luma); - luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma; - - sample[0] *= luma.x; - sample[1] *= luma.y; - sample[2] *= luma.z; - sample[3] *= luma.w; - - /* Protection against NaNs in the history buffer. - * This could be removed if some previous pass has already - * sanitized the input. */ - if (any(isnan(sample[0]))) { - sample[0] = vec3(0.0); - weight.x = 0.0; - } - if (any(isnan(sample[1]))) { - sample[1] = vec3(0.0); - weight.y = 0.0; - } - if (any(isnan(sample[2]))) { - sample[2] = vec3(0.0); - weight.z = 0.0; - } - if (any(isnan(sample[3]))) { - sample[3] = vec3(0.0); - weight.w = 0.0; - } + /* Compute cone footprint in screen space. */ + float cone_footprint = hit_dist * cone_tan; + float homcoord = ProjectionMatrix[2][3] * hit_vP.z + ProjectionMatrix[3][3]; + cone_footprint *= max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + cone_footprint *= ssrBrdfBias * 0.5; + /* Estimate a cone footprint to sample a corresponding mipmap level. */ + float mip = log2(cone_footprint * max_v2(vec2(textureSize(specroughBuffer, 0)))); - weight_acc += sum(weight); + vec4 radiance_mask = ssr_get_scene_color_and_mask(hit_vP, planar_index, mip); - /* Do not add light if ray has failed. */ - vec4 accum; - accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x); - accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y); - accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z); - accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w); - return accum; + ssr_accum += radiance_mask * weight; + weight_accum += weight; } void raytrace_resolve(ClosureInputGlossy cl_in, @@ -476,74 +307,55 @@ void raytrace_resolve(ClosureInputGlossy cl_in, inout ClosureEvalCommon cl_common, inout ClosureOutputGlossy cl_out) { -# ifdef FULLRES - ivec2 texel = ivec2(gl_FragCoord.xy); -# else - ivec2 texel = ivec2(gl_FragCoord.xy / 2.0); -# endif - /* Using world space */ - vec3 V = cl_common.V; - vec3 N = cl_in.N; - vec3 P = cl_common.P; - float roughness = cl_in.roughness; - float roughnessSquared = max(1e-3, sqr(roughness)); - - /* Resolve SSR */ - float cone_cos = cone_cosine(roughnessSquared); - float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; - cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - - vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; if (roughness < ssrMaxRoughness + 0.2) { - /* TODO optimize with textureGather */ - /* Doing these fetches early to hide latency. */ - vec4 hit_pdf; - hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r; - hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r; - hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r; - hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r; - - ivec4 hit_data[2]; - hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg; - hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg; - hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg; - hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg; - /* Find Planar Reflections affecting this pixel */ - PlanarData pd; - float planar_index; + int planar_index = -1; for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) { - pd = planars_data[i]; - - float fade = probe_attenuation_planar(pd, P); - fade *= probe_attenuation_planar_normal_roughness(pd, N, 0.0); - + float fade = probe_attenuation_planar(planars_data[i], cl_common.P); + fade *= probe_attenuation_planar_normal_roughness(planars_data[i], cl_in.N, 0.0); if (fade > 0.5) { - planar_index = float(i); + planar_index = i; break; } } - ssr_accum += get_ssr_samples(hit_pdf, - hit_data, - pd, - planar_index, - P, - N, - V, - roughnessSquared, - cone_tan, - source_uvs, - weight_acc); + vec3 V, P, N; + if (planar_index != -1) { + PlanarData pd = planars_data[planar_index]; + /* Evaluate everything in refected space. */ + P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq); + V = reflect(cl_common.V, pd.pl_normal); + N = reflect(cl_in.N, pd.pl_normal); + } + else { + V = cl_common.V; + P = cl_common.P; + N = cl_in.N; + } + + /* Using view space */ + vec3 vV = transform_direction(ViewMatrix, cl_common.V); + vec3 vP = transform_point(ViewMatrix, cl_common.P); + vec3 vN = transform_direction(ViewMatrix, cl_in.N); + + float roughness_squared = max(1e-3, sqr(roughness)); + float cone_cos = cone_cosine(roughness_squared); + float cone_tan = sqrt(1.0 - cone_cos * cone_cos) / cone_cos; + cone_tan *= mix(saturate(dot(vN, -vV) * 2.0), 1.0, roughness); /* Elongation fit */ + + vec2 sample_uv = uvcoordsvar.xy; + + resolve_reflection_sample( + planar_index, sample_uv, vP, vN, vV, roughness_squared, cone_tan, weight_acc, ssr_accum); } /* Compute SSR contribution */ - ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc); + ssr_accum *= safe_rcp(weight_acc); /* fade between 0.5 and 1.0 roughness */ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); @@ -555,13 +367,13 @@ CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy) void main() { - ivec2 texel = ivec2(gl_FragCoord.xy); - float depth = texelFetch(depthBuffer, texel, 0).r; + float depth = textureLod(maxzBuffer, uvcoordsvar.xy * hizUvScale.xy, 0.0).r; if (depth == 1.0) { discard; } + ivec2 texel = ivec2(gl_FragCoord.xy); vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba; vec3 brdf = speccol_roughness.rgb; float roughness = speccol_roughness.a; diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 7c375aabb62..dce50a7051e 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -15,13 +15,6 @@ struct Ray { vec3 direction; }; -vec3 raytrace_offset(vec3 P, vec3 Ng) -{ - /* TODO(fclem) better offset */ - const float epsilon_f = 1e-4; - return P + epsilon_f * Ng; -} - /* Inputs expected to be in viewspace. */ void raytrace_clip_ray_to_near_plane(inout Ray ray) { diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 5a09120916a..37624fc31ea 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -9,6 +9,10 @@ #define BTDF_BIAS 0.85 +uniform sampler2D refractColorBuffer; + +uniform float refractionDepth; + vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand) { float a2 = max(5e-6, roughnessSquared * roughnessSquared); @@ -75,10 +79,10 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness vec2 hit_uvs = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5; /* Texel footprint */ - vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy); + vec2 texture_size = vec2(textureSize(refractColorBuffer, 0).xy) / hizUvScale.xy; float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0); - vec3 spec = textureLod(colorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; + vec3 spec = textureLod(refractColorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; float mask = screen_border_mask(hit_uvs); return vec4(spec, mask); diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index e80dc1761f0..0acb35b2399 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -1,12 +1,5 @@ /** This describe the entire interface of the shader. */ -/* Samplers */ -uniform sampler2D colorBuffer; -uniform sampler2D depthBuffer; - -/* Uniforms */ -uniform float refractionDepth; - #define SURFACE_INTERFACE \ vec3 worldPosition; \ vec3 viewPosition; \ -- cgit v1.2.3 From d89fb77d894e8652608ebf78657bd199bfb3bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 15:34:11 +0100 Subject: EEVEE: GGX: Use distribution of visible normal for sampling This changes the sampling routine to use the method described in "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals" by Eric Heitz. http://jcgt.org/published/0007/04/01/slides.pdf This avoids generating bad rays and thus improve noise level in screen- space reflections / refraction. --- .../blender/draw/engines/eevee/eevee_lightprobes.c | 6 +- .../engines/eevee/shaders/bsdf_common_lib.glsl | 4 +- .../draw/engines/eevee/shaders/bsdf_lut_frag.glsl | 10 +-- .../engines/eevee/shaders/bsdf_sampling_lib.glsl | 74 ++++++++++++++++++---- .../draw/engines/eevee/shaders/btdf_lut_frag.glsl | 4 +- .../engines/eevee/shaders/effect_ssr_frag.glsl | 48 ++++++-------- .../shaders/lightprobe_filter_glossy_frag.glsl | 7 +- .../draw/engines/eevee/shaders/ssr_lib.glsl | 11 ++-- 8 files changed, 104 insertions(+), 60 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 0ce94b8f1b1..3e1d4a8aaa6 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -245,7 +245,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1); DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1); - DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1); + DRW_shgroup_uniform_float(grp, "roughness", &pinfo->roughness, 1); DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1); @@ -1045,8 +1045,8 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata, /* Disney Roughness */ pinfo->roughness = square_f(pinfo->roughness); /* Distribute Roughness across lod more evenly */ - pinfo->roughness = square_f(square_f(pinfo->roughness)); - CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */ + pinfo->roughness = square_f(pinfo->roughness); + CLAMP(pinfo->roughness, 1e-4f, 0.9999f); /* Avoid artifacts */ #if 1 /* Variable Sample count and bias (fast) */ switch (i) { diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 5f0fde134d1..c8eaa06094e 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -102,7 +102,7 @@ float D_ggx_opti(float NH, float a2) return M_PI * tmp * tmp; /* Doing RCP and mul a2 at the end */ } -float G1_Smith_GGX(float NX, float a2) +float G1_Smith_GGX_opti(float NX, float a2) { /* Using Brian Karis approach and refactoring by NX/NX * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV @@ -122,7 +122,7 @@ float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness) float NL = max(dot(N, L), 1e-8); float NV = max(dot(N, V), 1e-8); - float G = G1_Smith_GGX(NV, a2) * G1_Smith_GGX(NL, a2); /* Doing RCP at the end */ + float G = G1_Smith_GGX_opti(NV, a2) * G1_Smith_GGX_opti(NL, a2); /* Doing RCP at the end */ float D = D_ggx_opti(NH, a2); /* Denominator is canceled by G1_Smith */ diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl index 46ea8b747c8..4c1544654c1 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl @@ -25,7 +25,8 @@ void main() vec3 Xi = (vec3(i, j, 0.0) + 0.5) / sampleCount; Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI)); - vec3 H = sample_ggx(Xi, a2); /* Microfacet normal */ + /* Microfacet normal */ + vec3 H = sample_ggx(Xi, a, V); vec3 L = -reflect(V, H); float NL = L.z; @@ -33,9 +34,10 @@ void main() float NH = max(H.z, 0.0); float VH = max(dot(V, H), 0.0); - float G1_v = G1_Smith_GGX(NV, a2); - float G1_l = G1_Smith_GGX(NL, a2); - float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */ + float G1_v = G1_Smith_GGX_opti(NV, a2); + float G1_l = G1_Smith_GGX_opti(NL, a2); + /* See G1_Smith_GGX_opti for explanations. */ + float G_smith = 4.0 * NV * NL / (G1_v * G1_l); float brdf = (G_smith * VH) / (NH * NV); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index bbc79a2d05b..004d884dc75 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -1,4 +1,5 @@ +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) #pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) uniform sampler1D texHammersley; @@ -8,6 +9,11 @@ vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B) return T * vector.x + B * vector.y + N * vector.z; } +vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return vec3(dot(T, vector), dot(B, vector), dot(N, vector)); +} + #ifdef HAMMERSLEY_SIZE vec3 hammersley_3d(float i, float invsamplenbr) { @@ -22,9 +28,18 @@ vec3 hammersley_3d(float i, float invsamplenbr) /* -------------- BSDFS -------------- */ -float pdf_ggx_reflect(float NH, float a2) +#define USE_VISIBLE_NORMAL 1 + +float pdf_ggx_reflect(float NH, float NV, float VH, float alpha) { + float a2 = sqr(alpha); +#if USE_VISIBLE_NORMAL + float D = a2 / D_ggx_opti(NH, a2); + float G1 = NV * 2.0 / G1_Smith_GGX_opti(NV, a2); + return G1 * VH * D / NV; +#else return NH * a2 / D_ggx_opti(NH, a2); +#endif } float pdf_hemisphere() @@ -32,22 +47,50 @@ float pdf_hemisphere() return 0.5 * M_1_PI; } -vec3 sample_ggx(vec3 rand, float a2) +vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt) { +#if USE_VISIBLE_NORMAL + /* From: + * "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals" + * by Eric Heitz. + * http://jcgt.org/published/0007/04/01/slides.pdf + * View vector is expected to be in tangent space. */ + + /* Stretch view. */ + vec3 Th, Bh, Vh = normalize(vec3(alpha * Vt.xy, Vt.z)); + make_orthonormal_basis(Vh, Th, Bh); + /* Sample point with polar coordinates (r, phi). */ + float r = sqrt(rand.x); + float x = r * rand.y; + float y = r * rand.z; + float s = 0.5 * (1.0 + Vh.z); + y = (1.0 - s) * sqrt(1.0 - x * x) + s * y; + float z = sqrt(saturate(1.0 - x * x - y * y)); + /* Compute normal. */ + vec3 Hh = x * Th + y * Bh + z * Vh; + /* Unstretch. */ + vec3 Ht = normalize(vec3(alpha * Hh.xy, saturate(Hh.z))); + /* Microfacet Normal. */ + return Ht; +#else /* Theta is the cone angle. */ - float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */ - float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ + float z = sqrt((1.0 - rand.x) / (1.0 + sqr(alpha) * rand.x - rand.x)); /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * rand.y; float y = r * rand.z; - /* Microfacet Normal */ return vec3(x, y, z); +#endif } -vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH) +vec3 sample_ggx(vec3 rand, float alpha, vec3 V, vec3 N, vec3 T, vec3 B, out float pdf) { - vec3 Ht = sample_ggx(rand, a2); - NH = Ht.z; + vec3 Vt = world_to_tangent(V, N, T, B); + vec3 Ht = sample_ggx(rand, alpha, Vt); + float NH = saturate(Ht.z); + float NV = saturate(Vt.z); + float VH = saturate(dot(Vt, Ht)); + pdf = pdf_ggx_reflect(NH, NV, VH, alpha); return tangent_to_world(Ht, N, T, B); } @@ -69,18 +112,23 @@ vec3 sample_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B) } #ifdef HAMMERSLEY_SIZE -vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B) +vec3 sample_ggx(float nsample, + float inv_sample_count, + float alpha, + vec3 V, + vec3 N, + vec3 T, + vec3 B, + out float pdf) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - vec3 Ht = sample_ggx(Xi, a2); - return tangent_to_world(Ht, N, T, B); + return sample_ggx(Xi, alpha, V, N, T, B, pdf); } vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - vec3 Ht = sample_hemisphere(Xi); - return tangent_to_world(Ht, N, T, B); + return sample_hemisphere(Xi, N, T, B); } vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec3 T, vec3 B) diff --git a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl index 2ffe23a9197..2f1298e2707 100644 --- a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl @@ -37,7 +37,7 @@ void main() Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI)); /* Microfacet normal. */ - vec3 H = sample_ggx(Xi, a2); + vec3 H = sample_ggx(Xi, a2, V); float VH = dot(V, H); @@ -59,7 +59,7 @@ void main() float LH = dot(L, H); /* Balancing the adjustments made in G1_Smith. */ - float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2); + float G1_l = NL * 2.0 / G1_Smith_GGX_opti(NL, a2); /* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV) * pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index a9139b7a146..11aa85f2f2d 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -64,27 +64,22 @@ uniform sampler2D specroughBuffer; layout(location = 0) out vec4 hitData; -void do_planar_ssr( - int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPlaneNormal, vec3 vP, float a2, vec4 rand) +void do_planar_ssr(int index, + vec3 V, + vec3 N, + vec3 T, + vec3 B, + vec3 viewPlaneNormal, + vec3 vP, + float alpha, + vec4 rand) { - float NH; + float pdf; /* Microfacet normal */ - vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); - float pdf = pdf_ggx_reflect(NH, a2); - + vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf); vec3 R = reflect(-V, H); R = reflect(R, viewPlaneNormal); - /* If ray is bad (i.e. going below the plane) regenerate. */ - if (dot(R, viewPlaneNormal) > 0.0) { - /* Microfacet normal */ - vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); - pdf = pdf_ggx_reflect(NH, a2); - - R = reflect(-V, H); - R = reflect(R, viewPlaneNormal); - } - Ray ray; ray.origin = vP; ray.direction = R * 1e16; @@ -92,7 +87,7 @@ void do_planar_ssr( RayTraceParameters params; params.jitter = rand.y; params.trace_quality = ssrQuality; - params.roughness = a2; + params.roughness = alpha * alpha; HitData data; data.is_planar = true; @@ -104,26 +99,26 @@ void do_planar_ssr( hitData = encode_hit_data(data); } -void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) +void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float alpha, vec4 rand) { - float NH; + float pdf; /* Microfacet normal */ - vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); + vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf); vec3 R = reflect(-V, H); Ray ray; - ray.origin = vP; + ray.origin = vP + N * 1e-4; ray.direction = R * 1e16; RayTraceParameters params; params.thickness = ssrThickness; params.jitter = rand.y; params.trace_quality = ssrQuality; - params.roughness = a2; + params.roughness = alpha * alpha; HitData data; data.is_planar = true; - data.ray_pdf_inv = safe_rcp(pdf_ggx_reflect(NH, a2)); + data.ray_pdf_inv = safe_rcp(pdf); data.is_hit = raytrace(ray, params, true, data.hit_dir); data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); data.hit_dir -= ray.origin; @@ -170,8 +165,7 @@ void main() } float roughness = speccol_roughness.a; - float roughnessSquared = max(1e-3, roughness * roughness); - float a2 = roughnessSquared * roughnessSquared; + float alpha = max(1e-3, roughness * roughness); /* Early out */ if (roughness > ssrMaxRoughness + 0.2) { @@ -204,12 +198,12 @@ void main() tracePosition = transform_point(ViewMatrix, tracePosition); vec3 viewPlaneNormal = transform_direction(ViewMatrix, pd.pl_normal); - do_planar_ssr(i, vV, vN, vT, vB, viewPlaneNormal, tracePosition, a2, rand); + do_planar_ssr(i, vV, vN, vT, vB, viewPlaneNormal, tracePosition, alpha, rand); return; } } - do_ssr(vV, vN, vT, vB, vP, a2, rand); + do_ssr(vV, vN, vT, vB, vP, alpha, rand); } #else /* STEP_RESOLVE */ diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 35fdbcb715f..99cbf2839ad 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -3,7 +3,7 @@ #pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) uniform samplerCube probeHdr; -uniform float roughnessSquared; +uniform float roughness; uniform float texelSize; uniform float lodFactor; uniform float lodMax; @@ -52,7 +52,9 @@ void main() float weight = 0.0; vec3 out_radiance = vec3(0.0); for (float i = 0; i < sampleCount; i++) { - vec3 H = sample_ggx(i, invSampleCount, roughnessSquared, N, T, B); /* Microfacet normal */ + float pdf; + /* Microfacet normal */ + vec3 H = sample_ggx(i, invSampleCount, roughness, V, N, T, B, pdf); vec3 L = -reflect(V, H); float NL = dot(N, L); @@ -62,7 +64,6 @@ void main() /* Coarse Approximation of the mapping distortion * Unit Sphere -> Cubemap Face */ const float dist = 4.0 * M_PI / 6.0; - float pdf = pdf_ggx_reflect(NH, roughnessSquared); /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax); diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 37624fc31ea..612e95832e4 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -15,21 +15,20 @@ uniform float refractionDepth; vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand) { - float a2 = max(5e-6, roughnessSquared * roughnessSquared); + float alpha = max(0.002, roughnessSquared); /* Importance sampling bias */ rand.x = mix(rand.x, 0.0, BTDF_BIAS); vec3 T, B; - float NH; make_orthonormal_basis(N, T, B); - vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ - float pdf = pdf_ggx_reflect(NH, a2); + float pdf; + /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf); /* If ray is bad (i.e. going below the plane) regenerate. */ if (F_eta(ior, dot(H, V)) < 1.0) { - H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ - pdf = pdf_ggx_reflect(NH, a2); + H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), alpha, V, N, T, B, pdf); } vec3 vV = viewCameraVec(vP); -- cgit v1.2.3 From 793335f3e243f7a6f13d3d8a82c2bcb9925784bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 15:42:45 +0100 Subject: Cleanup: EEVEE: Use correct prefix for view space vectors --- .../engines/eevee/shaders/effect_ssr_frag.glsl | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index 11aa85f2f2d..cb090a320ce 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -65,10 +65,10 @@ uniform sampler2D specroughBuffer; layout(location = 0) out vec4 hitData; void do_planar_ssr(int index, - vec3 V, - vec3 N, - vec3 T, - vec3 B, + vec3 vV, + vec3 vN, + vec3 vT, + vec3 vB, vec3 viewPlaneNormal, vec3 vP, float alpha, @@ -76,13 +76,13 @@ void do_planar_ssr(int index, { float pdf; /* Microfacet normal */ - vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf); - vec3 R = reflect(-V, H); - R = reflect(R, viewPlaneNormal); + vec3 vH = sample_ggx(rand.xzw, alpha, vV, vN, vT, vB, pdf); + vec3 vR = reflect(-vV, vH); + vR = reflect(vR, viewPlaneNormal); Ray ray; ray.origin = vP; - ray.direction = R * 1e16; + ray.direction = vR * 1e16; RayTraceParameters params; params.jitter = rand.y; @@ -99,16 +99,16 @@ void do_planar_ssr(int index, hitData = encode_hit_data(data); } -void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float alpha, vec4 rand) +void do_ssr(vec3 vV, vec3 vN, vec3 vT, vec3 vB, vec3 vP, float alpha, vec4 rand) { float pdf; /* Microfacet normal */ - vec3 H = sample_ggx(rand.xzw, alpha, V, N, T, B, pdf); - vec3 R = reflect(-V, H); + vec3 vH = sample_ggx(rand.xzw, alpha, vV, vN, vT, vB, pdf); + vec3 vR = reflect(-vV, vH); Ray ray; - ray.origin = vP + N * 1e-4; - ray.direction = R * 1e16; + ray.origin = vP + vN * 1e-4; + ray.direction = vR * 1e16; RayTraceParameters params; params.thickness = ssrThickness; -- cgit v1.2.3 From 56bf4f3fb32641483aeb7870f9a6372a2867fbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 17:31:37 +0100 Subject: EEVEE: ScreenSpaceReflections: Add back support for planar reflections We now have a new buffer to output reflection depth. This buffer is only usefull for non planar SSR but we use it to tag the planar rays. This also touch the raytrace algo for planars to avoid degenerate lines on vert sharp reflections. --- source/blender/draw/engines/eevee/eevee_private.h | 1 + .../draw/engines/eevee/eevee_screen_raytrace.c | 3 ++ .../engines/eevee/shaders/effect_ssr_frag.glsl | 53 +++++++++++----------- .../draw/engines/eevee/shaders/raytrace_lib.glsl | 17 +++---- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index eb1c51f49dd..1ffd4a071f1 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -737,6 +737,7 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *ssr_normal_input; /* Textures from pool */ struct GPUTexture *ssr_specrough_input; struct GPUTexture *ssr_hit_output; + struct GPUTexture *ssr_hit_depth; /* Temporal Anti Aliasing */ int taa_reproject_sample; int taa_current_sample; diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 00004b28ef3..94b0161faf8 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -97,11 +97,13 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Ray-tracing output. */ effects->ssr_hit_output = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_RGBA16F, owner); + effects->ssr_hit_depth = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_R16F, owner); GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb, { GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), + GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_depth), }); return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER | @@ -173,6 +175,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "hitDepth", &effects->ssr_hit_depth, no_filter); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->filtered_radiance); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index cb090a320ce..11048a46f8e 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -25,6 +25,8 @@ uniform ivec2 halfresOffset; struct HitData { /** Hit direction scaled by intersection time. */ vec3 hit_dir; + /** Screen space [0..1] depth of the reflection hit position, or -1.0 for planar reflections. */ + float hit_depth; /** Inverse probability of ray spawning in this direction. */ float ray_pdf_inv; /** True if ray has hit valid geometry. */ @@ -33,27 +35,24 @@ struct HitData { bool is_planar; }; -vec4 encode_hit_data(HitData data) +void encode_hit_data(HitData data, vec3 hit_sP, vec3 vP, out vec4 hit_data, out float hit_depth) { - vec4 encoded_data; - encoded_data.xyz = data.hit_dir; - /* Encode planar in Z sign. */ - /* TODO fixme */ - // encoded_data.z = data.is_planar ? -encoded_data.z : encoded_data.z; + vec3 hit_vP = get_view_space_from_depth(hit_sP.xy, hit_sP.z); + hit_data.xyz = hit_vP - vP; + hit_depth = data.is_planar ? -1.0 : hit_sP.z; /* Record 1.0 / pdf to reduce the computation in the resolve phase. */ /* Encode hit validity in sign. */ - encoded_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0); - return encoded_data; + hit_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0); } -HitData decode_hit_data(vec4 encoded_data) +HitData decode_hit_data(vec4 hit_data, float hit_depth) { HitData data; - data.hit_dir.xyz = encoded_data.xyz; - /* TODO fixme */ - data.is_planar = false; - data.ray_pdf_inv = abs(encoded_data.w); - data.is_hit = (encoded_data.w > 0.0); + data.hit_dir.xyz = hit_data.xyz; + data.hit_depth = hit_depth; + data.is_planar = (hit_depth == -1.0); + data.ray_pdf_inv = abs(hit_data.w); + data.is_hit = (hit_data.w > 0.0); return data; } @@ -63,6 +62,7 @@ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; layout(location = 0) out vec4 hitData; +layout(location = 1) out float hitDepth; void do_planar_ssr(int index, vec3 vV, @@ -89,14 +89,13 @@ void do_planar_ssr(int index, params.trace_quality = ssrQuality; params.roughness = alpha * alpha; + vec3 hit_sP; HitData data; data.is_planar = true; data.ray_pdf_inv = safe_rcp(pdf); - data.is_hit = raytrace_planar(ray, params, index, data.hit_dir); - data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); - data.hit_dir -= ray.origin; + data.is_hit = raytrace_planar(ray, params, index, hit_sP); - hitData = encode_hit_data(data); + encode_hit_data(data, hit_sP, ray.origin, hitData, hitDepth); } void do_ssr(vec3 vV, vec3 vN, vec3 vT, vec3 vB, vec3 vP, float alpha, vec4 rand) @@ -116,14 +115,13 @@ void do_ssr(vec3 vV, vec3 vN, vec3 vT, vec3 vB, vec3 vP, float alpha, vec4 rand) params.trace_quality = ssrQuality; params.roughness = alpha * alpha; + vec3 hit_sP; HitData data; - data.is_planar = true; + data.is_planar = false; data.ray_pdf_inv = safe_rcp(pdf); - data.is_hit = raytrace(ray, params, true, data.hit_dir); - data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); - data.hit_dir -= ray.origin; + data.is_hit = raytrace(ray, params, true, hit_sP); - hitData = encode_hit_data(data); + encode_hit_data(data, hit_sP, ray.origin, hitData, hitDepth); } in vec4 uvcoordsvar; @@ -135,12 +133,12 @@ void main() HitData data; data.is_planar = false; - data.ray_pdf_inv = safe_rcp(0.0); + data.ray_pdf_inv = 0.0; data.is_hit = false; data.hit_dir = vec3(0.0, 0.0, 0.0); /* Default: not hits. */ - hitData = encode_hit_data(data); + encode_hit_data(data, data.hit_dir, data.hit_dir, hitData, hitDepth); /* Early out */ /* We can't do discard because we don't clear the render target. */ @@ -212,6 +210,7 @@ uniform sampler2D colorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; uniform sampler2D hitBuffer; +uniform sampler2D hitDepth; in vec4 uvcoordsvar; @@ -264,7 +263,9 @@ void resolve_reflection_sample(int planar_index, inout float weight_accum, inout vec4 ssr_accum) { - HitData data = decode_hit_data(texture(hitBuffer, sample_uv * ssrUvScale)); + vec4 hit_data = texture(hitBuffer, sample_uv * ssrUvScale); + float hit_depth = texture(hitDepth, sample_uv * ssrUvScale).r; + HitData data = decode_hit_data(hit_data, hit_depth); float hit_dist = length(data.hit_dir); diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index dce50a7051e..e2aad867901 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -43,12 +43,12 @@ void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray) ray.direction.zw += bias; ray.direction -= ray.origin; - float ray_len_sqr = len_squared(ray.direction.xyz); /* If the line is degenerate, make it cover at least one pixel * to not have to handle zero-pixel extent as a special case later */ - if (ray_len_sqr < 0.00001) { - ray.direction.xy = vec2(0.0, 0.0001); + if (len_squared(ray.direction.xy) < 0.00001) { + ray.direction.xy = vec2(0.0, 0.01); } + float ray_len_sqr = len_squared(ray.direction.xyz); /* Make ray.direction cover one pixel. */ bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y); ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x); @@ -166,8 +166,6 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out } ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray); - /* Avoid no iteration. */ - ssray.max_time = max(ssray.max_time, 1.1); /* Planar Reflections have X mirrored. */ ssray.origin.x = 1.0 - ssray.origin.x; @@ -177,9 +175,10 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out float depth_sample = get_depth_from_view_z(ray.origin.z); float delta = depth_sample - ssray.origin.z; - /* Cross at least one pixel. */ - float t = 1.001, time = 1.001; - bool hit = false; + float t = 0.0, time = 0.0; + /* On very sharp reflections, the ray can be perfectly aligned with the view direction + * making the tracing useless. Bypass tracing in this case. */ + bool hit = (ssray.max_time < 1.0); const float max_steps = 255.0; for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) { float stride = 1.0 + iter * params.trace_quality; @@ -205,6 +204,8 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta))); hit_position = ssray.origin.xyz + ssray.direction.xyz * time; + /* Planar Reflections have X mirrored. */ + hit_position.x = 1.0 - hit_position.x; return hit; } -- cgit v1.2.3 From 5ab2252a6631bfa58a3ceb57f9778253a477e642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 17:39:56 +0100 Subject: Fix T86429 EEVEE: Ambient occlusion broken on some platform This was cause by a division by 0 if the ray direction had no depth difference. Adding a small epsilon fix the issue. --- source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index e2aad867901..c47a8bdc4e9 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -48,6 +48,11 @@ void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray) if (len_squared(ray.direction.xy) < 0.00001) { ray.direction.xy = vec2(0.0, 0.01); } + /* Avoid divide by 0 error in line_unit_box_intersect_dist, leading to undefined behavior + * (see T86429). */ + if (ray.direction.z == 0.0) { + ray.direction.z = 0.0001; + } float ray_len_sqr = len_squared(ray.direction.xyz); /* Make ray.direction cover one pixel. */ bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y); -- cgit v1.2.3 From 352385d1097adf7c7bc147a31c1608795873ac21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 17:43:10 +0100 Subject: Cleanup: EEVEE: Remove unused function and fix comment --- .../draw/engines/eevee/shaders/ambient_occlusion_lib.glsl | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index a0bfd440dd9..4398247472d 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -50,14 +50,6 @@ OcclusionData unpack_occlusion_data(vec4 v) return OcclusionData((1.0 - v) * vec4(1, -1, 1, -1) * M_PI, 0.0); } -/* Returns maximum screen distance an AO ray can travel for a given view depth, in NDC space. */ -vec2 get_ao_area(float view_depth, float radius) -{ - float homcco = ProjectionMatrix[2][3] * view_depth + ProjectionMatrix[3][3]; - float max_dist = radius / homcco; - return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist; -} - vec2 get_ao_noise(void) { vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; @@ -108,7 +100,7 @@ float search_horizon(vec3 vI, float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r; if (depth == 1.0 && inverted == 0.0) { - /* Skip background. This avoids issues with the thickness heuristic. */ + /* Skip background. Avoids making shadow on the geometry near the far plane. */ continue; } @@ -146,7 +138,6 @@ OcclusionData occlusion_search( } vec2 noise = get_ao_noise(); - vec2 area = get_ao_area(vP.z, radius); vec2 dir = get_ao_dir(noise.x); vec2 uv = get_uvs_from_view(vP); vec3 vI = ((ProjectionMatrix[3][3] == 0.0) ? normalize(-vP) : vec3(0.0, 0.0, 1.0)); -- cgit v1.2.3 From 4cd9a1164b5a184ca957b977f27584ec61cc3ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 10 Mar 2021 17:53:08 +0100 Subject: EEVEE: ScreenSpaceReflections: Improve minimal hit threshold This makes the hit delta threshold dependant on the ray angle. If the ray is more aligned with the view, its intersection threshold gets bigger to avoid going through geometry. This improves reflections and fix T86448 refraction issue. --- source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index c47a8bdc4e9..8975397b62a 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -148,7 +148,7 @@ bool raytrace(Ray ray, /* Check if the ray is below the surface ... */ hit = (delta < 0.0); /* ... and above it with the added thickness. */ - hit = hit && (delta > ss_p.z - ss_p.w); + hit = hit && (delta > ss_p.z - ss_p.w || abs(delta) < abs(ssray.direction.z * stride)); } /* Discard backface hits. */ hit = hit && !(discard_backface && prev_delta < 0.0); -- cgit v1.2.3 From 9ef24d5aaa190b3429756368f29c9acfaf2b2605 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 10 Mar 2021 22:19:36 +0100 Subject: Geometry Nodes: fix error adding a value node Caused by own rBcf2933c38a34 which changed the poll on this node to be "shading-only", but this one is actually supported. --- source/blender/nodes/shader/nodes/node_shader_value.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index a1ef65a5655..495c8d12824 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -50,7 +50,7 @@ void register_node_type_sh_value(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0); + sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0); node_type_socket_templates(&ntype, nullptr, sh_node_value_out); node_type_gpu(&ntype, gpu_shader_value); ntype.expand_in_mf_network = sh_node_value_expand_in_mf_network; -- cgit v1.2.3 From 85623f6a5590e99c9d821bba53f8b5fe3812a47d Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 10 Mar 2021 22:10:05 -0500 Subject: UI: Add Copy Full Data Path to RMB menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds an operator to the RMB-menu "Copy Full Data Path“, to copy the full RNA path to the clipboard. It aims to complement "Copy Data Path“, which only copies the part of the path that is needed for drivers, but for writing addons, etc. it is useful to have an option that gives the full data path. Similar patch have been submitted before, see D763 and D2746 This time I did not split the operator (as D2746) and does not contain the UI reorganization (as D763) Note, the fixes from D2746 were committed in rB09eac0159db8 so that patch can be closed. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D10539 --- source/blender/editors/interface/interface_context_menu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index edfd1ecd539..91c19ff2850 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -936,6 +936,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"), ICON_NONE, "UI_OT_copy_data_path_button"); + uiItemBooleanO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Full Data Path"), + ICON_NONE, + "UI_OT_copy_data_path_button", + "full_path", + true); if (ptr->owner_id && !is_whole_array && ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) { -- cgit v1.2.3 From 28e83bca9d997366aa174bf3ea55fe1dae8866e5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 11 Mar 2021 11:35:02 +0100 Subject: Geometry Nodes: improve handling when the same socket is connected twice The multi-input-socket cannot be connected to the same socket twice currently. However, it is still possible to achieve this using an intermediate reroute node. In this case the origin socket should be listed twice in the `linked_sockets_` list. Higher level functions can still deduplicate the list of they want. --- source/blender/nodes/intern/node_tree_ref.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 775e16d0a29..a66b7b1d2fe 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -181,7 +181,7 @@ void NodeTreeRef::find_origins_skipping_reroutes(InputSocketRef &socket, this->find_origins_skipping_reroutes(*direct_origin->node_->inputs_[0], r_origins); } else { - r_origins.append_non_duplicates(direct_origin); + r_origins.append(direct_origin); } } } -- cgit v1.2.3 From 74f3edc3431875223c1045f918729a43f94a6924 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhary Date: Thu, 11 Mar 2021 11:56:40 +0100 Subject: Fix T86458: Simple Subdivision node does not preserve vertex groups Differential Revision: https://developer.blender.org/D10683 --- source/blender/nodes/geometry/nodes/node_geo_subdivide.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc index b5731851229..06c5586a3ff 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc @@ -91,7 +91,8 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); BKE_mesh_calc_normals(mesh_out); - geometry_set.replace_mesh(mesh_out); + MeshComponent &mesh_component = geometry_set.get_component_for_write(); + mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out); BKE_subdiv_free(subdiv); -- cgit v1.2.3 From 5f1f233dc97de34f6be0f51edd3cbf2d8247fbda Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 11 Mar 2021 12:23:01 +0100 Subject: Spreadsheet: expore more domains and point cloud data Ref T86135. Differential Revision: https://developer.blender.org/D10681 --- release/scripts/startup/bl_ui/space_spreadsheet.py | 3 + .../editors/space_spreadsheet/space_spreadsheet.cc | 2 +- .../space_spreadsheet/spreadsheet_from_geometry.cc | 147 +++++++++++++++++---- source/blender/makesdna/DNA_space_types.h | 7 +- source/blender/makesrna/intern/rna_space.c | 72 ++++++++++ 5 files changed, 201 insertions(+), 30 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py index 1d124019ce8..1ba650fa096 100644 --- a/release/scripts/startup/bl_ui/space_spreadsheet.py +++ b/release/scripts/startup/bl_ui/space_spreadsheet.py @@ -31,6 +31,9 @@ class SPREADSHEET_HT_header(bpy.types.Header): pinned_id = space.pinned_id used_id = pinned_id if pinned_id else context.active_object + layout.prop(space, "geometry_component_type", text="") + layout.prop(space, "attribute_domain", text="") + if used_id: layout.label(text=used_id.name, icon="OBJECT_DATA") diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 53424c60d59..8ab1baaaea3 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -126,7 +126,7 @@ static std::unique_ptr generate_spreadsheet_drawer(const bCon return {}; } Object *object_orig = (Object *)used_id; - if (object_orig->type != OB_MESH) { + if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) { return {}; } Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc index 8459973ed4a..35dc9d62aa3 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc @@ -332,10 +332,11 @@ static void add_columns_for_attribute(const ReadAttribute *attribute, } } -static GeometrySet get_display_geometry_set(Object *object_eval) +static GeometrySet get_display_geometry_set(Object *object_eval, + const GeometryComponentType used_component_type) { GeometrySet geometry_set; - if (object_eval->mode == OB_MODE_EDIT) { + if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); if (mesh == nullptr) { return geometry_set; @@ -354,10 +355,87 @@ static GeometrySet get_display_geometry_set(Object *object_eval) return geometry_set; } -static Span filter_visible_mesh_vertex_rows(const bContext *C, - Object *object_eval, - const MeshComponent *component, - ResourceCollector &resources) +using IsVertexSelectedFn = FunctionRef; + +static void get_selected_vertex_indices(const Mesh &mesh, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector &r_vertex_indices) +{ + for (const int i : IndexRange(mesh.totvert)) { + if (is_vertex_selected_fn(i)) { + r_vertex_indices.append(i); + } + } +} + +static void get_selected_corner_indices(const Mesh &mesh, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector &r_corner_indices) +{ + for (const int i : IndexRange(mesh.totloop)) { + const MLoop &loop = mesh.mloop[i]; + if (is_vertex_selected_fn(loop.v)) { + r_corner_indices.append(i); + } + } +} + +static void get_selected_polygon_indices(const Mesh &mesh, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector &r_polygon_indices) +{ + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + bool is_selected = true; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + if (!is_vertex_selected_fn(loop.v)) { + is_selected = false; + break; + } + } + if (is_selected) { + r_polygon_indices.append(poly_index); + } + } +} + +static void get_selected_edge_indices(const Mesh &mesh, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector &r_edge_indices) +{ + for (const int i : IndexRange(mesh.totedge)) { + const MEdge &edge = mesh.medge[i]; + if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) { + r_edge_indices.append(i); + } + } +} + +static void get_selected_indices_on_domain(const Mesh &mesh, + const AttributeDomain domain, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector &r_indices) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices); + case ATTR_DOMAIN_POLYGON: + return get_selected_polygon_indices(mesh, is_vertex_selected_fn, r_indices); + case ATTR_DOMAIN_CORNER: + return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices); + case ATTR_DOMAIN_EDGE: + return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices); + default: + return; + } +} + +static Span filter_mesh_elements_by_selection(const bContext *C, + Object *object_eval, + const MeshComponent *component, + const AttributeDomain domain, + ResourceCollector &resources) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const bool show_only_selected = sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY; @@ -372,47 +450,55 @@ static Span filter_visible_mesh_vertex_rows(const bContext *C, int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX); if (orig_indices != nullptr) { /* Use CD_ORIGINDEX layer if it exists. */ - for (const int i_eval : IndexRange(mesh_eval->totvert)) { - const int i_orig = orig_indices[i_eval]; - if (i_orig >= 0 && i_orig < bm->totvert) { - BMVert *vert = bm->vtable[i_orig]; - if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) { - visible_rows.append(i_eval); - } + auto is_vertex_selected = [&](int vertex_index) -> bool { + const int i_orig = orig_indices[vertex_index]; + if (i_orig < 0) { + return false; } - } + if (i_orig >= bm->totvert) { + return false; + } + BMVert *vert = bm->vtable[i_orig]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }; + get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows); } else if (mesh_eval->totvert == bm->totvert) { /* Use a simple heuristic to match original vertices to evaluated ones. */ - for (const int i : IndexRange(mesh_eval->totvert)) { - BMVert *vert = bm->vtable[i]; - if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) { - visible_rows.append(i); - } - } + auto is_vertex_selected = [&](int vertex_index) -> bool { + BMVert *vert = bm->vtable[vertex_index]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }; + get_selected_indices_on_domain(*mesh_eval, domain, is_vertex_selected, visible_rows); } /* This is safe, because the vector lives in the resource collector. */ return visible_rows.as_span(); } /* No filter is used. */ - const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_POINT); + const int domain_size = component->attribute_domain_size(domain); return IndexRange(domain_size).as_span(); } std::unique_ptr spreadsheet_drawer_from_geometry_attributes(const bContext *C, Object *object_eval) { + SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; + const GeometryComponentType component_type = (GeometryComponentType) + sspreadsheet->geometry_component_type; + /* Create a resource collector that owns stuff that needs to live until drawing is done. */ std::unique_ptr resources = std::make_unique(); - GeometrySet &geometry_set = resources->add_value(get_display_geometry_set(object_eval), - "geometry set"); + GeometrySet &geometry_set = resources->add_value( + get_display_geometry_set(object_eval, component_type), "geometry set"); - const AttributeDomain domain = ATTR_DOMAIN_POINT; - const GeometryComponentType component_type = GEO_COMPONENT_TYPE_MESH; const GeometryComponent *component = geometry_set.get_component_for_read(component_type); if (component == nullptr) { return {}; } + if (!component->attribute_domain_supported(domain)) { + return {}; + } Vector attribute_names = get_sorted_attribute_names_to_display(*component, domain); @@ -425,9 +511,14 @@ std::unique_ptr spreadsheet_drawer_from_geometry_attributes(c } /* The filter below only works for mesh vertices currently. */ - BLI_assert(domain == ATTR_DOMAIN_POINT && component_type == GEO_COMPONENT_TYPE_MESH); - Span visible_rows = filter_visible_mesh_vertex_rows( - C, object_eval, static_cast(component), *resources); + Span visible_rows; + if (component_type == GEO_COMPONENT_TYPE_MESH) { + visible_rows = filter_mesh_elements_by_selection( + C, object_eval, static_cast(component), domain, *resources); + } + else { + visible_rows = IndexRange(component->attribute_domain_size(domain)).as_span(); + } const int domain_size = component->attribute_domain_size(domain); return std::make_unique( diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index b18add0a826..300956c28fd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1858,7 +1858,12 @@ typedef struct SpaceSpreadsheet { /* eSpaceSpreadsheet_FilterFlag. */ uint8_t filter_flag; - char _pad1[7]; + /* #GeometryComponentType. */ + uint8_t geometry_component_type; + /* #AttributeDomain. */ + uint8_t attribute_domain; + + char _pad1[5]; } SpaceSpreadsheet; /** \} */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 574c4e98819..9e8e9030925 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -25,6 +25,8 @@ #include "BLT_translation.h" +#include "BKE_attribute.h" +#include "BKE_geometry_set.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_movieclip.h" @@ -2991,6 +2993,48 @@ static void rna_SpaceSpreadsheet_pinned_id_set(PointerRNA *ptr, sspreadsheet->pinned_id = value.data; } +static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *ptr) +{ + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data; + if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) { + sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT; + } +} + +const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UNUSED(C), + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data; + EnumPropertyItem *item_array = NULL; + int items_len = 0; + for (const EnumPropertyItem *item = rna_enum_attribute_domain_items; item->identifier != NULL; + item++) { + if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_MESH) { + if (!ELEM(item->value, + ATTR_DOMAIN_CORNER, + ATTR_DOMAIN_EDGE, + ATTR_DOMAIN_POINT, + ATTR_DOMAIN_POLYGON)) { + continue; + } + } + if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) { + if (item->value != ATTR_DOMAIN_POINT) { + continue; + } + } + RNA_enum_item_add(&item_array, &items_len, item); + } + RNA_enum_item_end(&item_array, &items_len); + + *r_free = true; + return item_array; +} + #else static const EnumPropertyItem dt_uv_items[] = { @@ -7196,6 +7240,20 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) PropertyRNA *prop; StructRNA *srna; + static const EnumPropertyItem geometry_component_type_items[] = { + {GEO_COMPONENT_TYPE_MESH, + "MESH", + ICON_MESH_DATA, + "Mesh", + "Mesh component containing point, corner, edge and polygon data"}, + {GEO_COMPONENT_TYPE_POINT_CLOUD, + "POINTCLOUD", + ICON_POINTCLOUD_DATA, + "Point Cloud", + "Point cloud component containing only point data"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space"); RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data"); @@ -7210,6 +7268,20 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Show Only Selected", "Only include rows that correspond to selected elements"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + + prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, geometry_component_type_items); + RNA_def_property_ui_text( + prop, "Geometry Component", "Part of the geometry to display data from"); + RNA_def_property_update(prop, + NC_SPACE | ND_SPACE_SPREADSHEET, + "rna_SpaceSpreadsheet_geometry_component_type_update"); + + prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceSpreadsheet_attribute_domain_itemf"); + RNA_def_property_ui_text(prop, "Attribute Domain", "Attribute domain to display"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); } void RNA_def_space(BlenderRNA *brna) -- cgit v1.2.3 From 42c5303409928f5cbc069baf2866ca6330119cce Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:01:27 +0100 Subject: Cleanup: Typos in comments (window-manager files) Typos from a509e79a4c77. Looks like issues with an automated cleanup tool. --- source/blender/windowmanager/intern/wm.c | 4 ++-- source/blender/windowmanager/intern/wm_event_system.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index c5a429d7839..836bca98f65 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -642,10 +642,10 @@ void WM_main(bContext *C) /* Per window, all events to the window, screen, area and region handlers. */ wm_event_do_handlers(C); - /* Wvents have left notes about changes, we handle and cache it. */ + /* Events have left notes about changes, we handle and cache it. */ wm_event_do_notifiers(C); - /* Wxecute cached changes draw. */ + /* Execute cached changes draw. */ wm_draw_update(C); } } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 470952956c8..a39200537d5 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1319,7 +1319,7 @@ static int wm_operator_invoke(bContext *C, op->flag |= OP_IS_INVOKE; } - /* /initialize setting from previous run. */ + /* Initialize setting from previous run. */ if (!is_nested_call && use_last_properties) { /* Not called by py script. */ WM_operator_last_properties_init(op); } @@ -3190,7 +3190,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { event->type = EVT_DROP; - /* Vreate customdata, first free existing. */ + /* Create customdata, first free existing. */ if (event->customdata) { if (event->customdatafree) { MEM_freeN(event->customdata); @@ -3201,7 +3201,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv event->customdata = &wm->drags; event->customdatafree = 1; - /* Vlear drop icon. */ + /* Clear drop icon. */ screen->do_draw_drag = true; /* restore cursor (disabled, see wm_dragdrop.c) */ -- cgit v1.2.3 From 018fffbe77414e2d6b80dc50d5f3d2d5bbf71169 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:02:47 +0100 Subject: Fix failing assert when loading file with untraceable custom asset library When loading a file with an asset browser open, and it showed a custom asset library that can't be found currently (e.g. because the file is from somebody else), the `BLI_assert(0)` in `rna_FileAssetSelectParams_asset_library_get()` would fail. There was code to handle this case already, but unlike I thought it didn't run right after file read. Now it does. --- source/blender/editors/space_file/space_file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 83bb8abf5d8..039ab3d6907 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -193,6 +193,8 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->runtime == NULL) { sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); } + /* Validate the params right after file read. */ + fileselect_refresh_params(sfile); } static void file_exit(wmWindowManager *wm, ScrArea *area) -- cgit v1.2.3 From f59ff9e03a633f64f9587eb67eee7913fed685a8 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:14:22 +0100 Subject: Fix crash when showing NLA actions in the Outliner Caused by 2e221de4ceee in combination with 4292bb060d59. In the former I forgot to set the name for NLA actions in the new code design, in the latter I made it an assumtion that tree element types using the new design set the name. The following commit will make this assumption explicit with an assert. --- source/blender/editors/space_outliner/tree/tree_element.cc | 2 +- source/blender/editors/space_outliner/tree/tree_element_nla.cc | 4 +++- source/blender/editors/space_outliner/tree/tree_element_nla.hh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 25bd9a53cf8..116a2e4d3c3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -52,7 +52,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te case TSE_NLA_TRACK: return new TreeElementNLATrack(legacy_te, *static_cast(idv)); case TSE_NLA_ACTION: - return new TreeElementNLAAction(legacy_te); + return new TreeElementNLAAction(legacy_te, *static_cast(idv)); case TSE_GP_LAYER: return new TreeElementGPencilLayer(legacy_te, *static_cast(idv)); case TSE_R_LAYER_BASE: diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc index 5d4ec53e60c..65832e8f981 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc @@ -70,9 +70,11 @@ void TreeElementNLATrack::expand(SpaceOutliner &space_outliner) const /* -------------------------------------------------------------------- */ -TreeElementNLAAction::TreeElementNLAAction(TreeElement &legacy_te) : AbstractTreeElement(legacy_te) +TreeElementNLAAction::TreeElementNLAAction(TreeElement &legacy_te, const bAction &action) + : AbstractTreeElement(legacy_te) { BLI_assert(legacy_te.store_elem->type == TSE_NLA_ACTION); + legacy_te.name = action.id.name + 2; } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh index c94287ce576..7cbc8689483 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh @@ -46,7 +46,7 @@ class TreeElementNLATrack final : public AbstractTreeElement { class TreeElementNLAAction final : public AbstractTreeElement { public: - TreeElementNLAAction(TreeElement &legacy_te); + TreeElementNLAAction(TreeElement &legacy_te, const bAction &action); }; } // namespace blender::ed::outliner -- cgit v1.2.3 From fade765bf3488676141b28556969130eef9b70bb Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:19:25 +0100 Subject: Outliner: Add assert to make assumption for new code design explicit There was an implicit assumption that tree element types using the new code design set their name on creation. Use an assert to make this explicit. See f59ff9e03a633, which was an error because of this broken assumption. --- source/blender/editors/space_outliner/outliner_tree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 6319b890b3b..36a9549c9b2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -889,6 +889,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some * support this, eventually this should replace `TreeElement` entirely. */ te->type = outliner_tree_element_type_create(type, te, idv); + if (te->type) { + /* Element types ported to the new design are expected to have their name set at this point! */ + BLI_assert(te->name != NULL); + } if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { /* pass */ -- cgit v1.2.3 From d4d03f736b85f9db0d738428cf9521b2084232db Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 11 Mar 2021 13:28:06 +0100 Subject: Fix (unreported): crash on undo when using pinned id in spreadsheet Now the behavior is the same as in the properties editor, as far as I can tell. --- release/scripts/startup/bl_operators/spreadsheet.py | 2 +- source/blender/blenloader/intern/readfile.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py index a2f9b2ad412..fa6568f6f11 100644 --- a/release/scripts/startup/bl_operators/spreadsheet.py +++ b/release/scripts/startup/bl_operators/spreadsheet.py @@ -24,7 +24,7 @@ class SPREADSHEET_OT_toggle_pin(bpy.types.Operator): '''Turn on or off pinning''' bl_idname = "spreadsheet.toggle_pin" bl_label = "Toggle Pin" - bl_options = {'REGISTER', 'UNDO'} + bl_options = {'REGISTER'} @classmethod def poll(cls, context): diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index de7353d827a..302abf35f1c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2985,6 +2985,12 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, sclip->scopes.ok = 0; } + else if (sl->spacetype == SPACE_SPREADSHEET) { + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; + + sspreadsheet->pinned_id = restore_pointer_by_name( + id_map, sspreadsheet->pinned_id, USER_IGNORE); + } } } } -- cgit v1.2.3 From 0f60dbe4bf5227c2f8f21026f11ffd9703101687 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:39:06 +0100 Subject: Cleanup: Pass anim-data directly to Outliner anim-data tree element constructor Rather than letting the `TreeElementAnimData` constructor take an ID from which we get the animation-data based on an assumption on how it's stored, let the constructor take the animation-data directly. That way we further centralize the assumptions on the data passed to the element creation to `tree_element_create()`. The following commit will add a comment explaining the plan to entirely get rid of those assumptions in the future. --- source/blender/editors/space_outliner/tree/tree_element.cc | 3 ++- source/blender/editors/space_outliner/tree/tree_element_anim_data.cc | 4 ++-- source/blender/editors/space_outliner/tree/tree_element_anim_data.hh | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 116a2e4d3c3..d537bdfc99c 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -18,6 +18,7 @@ * \ingroup spoutliner */ +#include "DNA_anim_types.h" #include "DNA_listBase.h" #include "tree_element_anim_data.hh" @@ -44,7 +45,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te case TSE_SOME_ID: return TreeElementID::createFromID(legacy_te, id); case TSE_ANIM_DATA: - return new TreeElementAnimData(legacy_te, id); + return new TreeElementAnimData(legacy_te, *reinterpret_cast(id).adt); case TSE_DRIVER_BASE: return new TreeElementDriverBase(legacy_te, *static_cast(idv)); case TSE_NLA: diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc index 5a9568ea906..c0fef7c98e2 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -32,8 +32,8 @@ namespace blender::ed::outliner { -TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id) - : AbstractTreeElement(legacy_te), anim_data_(*reinterpret_cast(id).adt) +TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, AnimData &anim_data) + : AbstractTreeElement(legacy_te), anim_data_(anim_data) { BLI_assert(legacy_te.store_elem->type == TSE_ANIM_DATA); /* this element's info */ diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh index 8114277b6d6..95d08cd20b7 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh @@ -30,7 +30,7 @@ class TreeElementAnimData final : public AbstractTreeElement { AnimData &anim_data_; public: - TreeElementAnimData(TreeElement &legacy_te, ID &id); + TreeElementAnimData(TreeElement &legacy_te, AnimData &anim_data); void expand(SpaceOutliner &space_outliner) const override; -- cgit v1.2.3 From ba996ddb3a3a49065d26ff1010790b17bc8709ec Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 13:47:16 +0100 Subject: Cleanup: Add comment explaining plan for new Outliner tree-element code design Explains how we can get rid of implicit assumptions and `void *` arguments/storage in the future. --- source/blender/editors/space_outliner/tree/tree_element.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index d537bdfc99c..6fe3f341fd3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -37,10 +37,20 @@ namespace blender::ed::outliner { static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv) { - /* Would be nice to get rid of void * here, can we somehow expect the right type right away? - * Perfect forwarding maybe, once the API is C++ only? */ ID &id = *static_cast(idv); + /* + * The following calls make an implicit assumption about what data was passed to the `idv` + * argument of #outliner_add_element(). The old code does this already, here we just centralize + * it as much as possible for now. Would be nice to entirely get rid of that, no more `void *`. + * + * Once #outliner_add_element() is sufficiently simplified, it should be replaced by a C++ call. + * It could take the derived type as template paramenter (e.g. #TreeElementAnimData) and use C++ + * perfect forwarding to pass any data to the type's constructor. + * If general Outliner code wants to access the data, they can query that through the derived + * element type then. There's no need for `void *` anymore then. + */ + switch (type) { case TSE_SOME_ID: return TreeElementID::createFromID(legacy_te, id); -- cgit v1.2.3 From f4f8b6dde32b0438e0b97a6d8ebeb89802987127 Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Wed, 3 Mar 2021 14:35:50 +0100 Subject: Cycles: Change device-only memory to actually only allocate on the device This patch changes the `MEM_DEVICE_ONLY` type to only allocate on the device and fail if that is not possible anymore because out-of-memory (since OptiX acceleration structures may not be allocated in host memory). It also fixes high peak memory usage during OptiX acceleration structure building. Reviewed By: brecht Maniphest Tasks: T85985 Differential Revision: https://developer.blender.org/D10535 --- intern/cycles/bvh/bvh_optix.cpp | 4 ++-- intern/cycles/device/cuda/device_cuda_impl.cpp | 12 +++++++++--- intern/cycles/device/device_cpu.cpp | 5 ++--- intern/cycles/device/device_denoising.h | 3 ++- intern/cycles/device/device_memory.h | 4 ++-- intern/cycles/device/device_optix.cpp | 23 ++++++++++++++++------- 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp index e094f339ede..d630e8965dc 100644 --- a/intern/cycles/bvh/bvh_optix.cpp +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -27,8 +27,8 @@ BVHOptiX::BVHOptiX(const BVHParams ¶ms_, Device *device) : BVH(params_, geometry_, objects_), traversable_handle(0), - as_data(device, params_.top_level ? "optix tlas" : "optix blas"), - motion_transform_data(device, "optix motion transform") + as_data(device, params_.top_level ? "optix tlas" : "optix blas", false), + motion_transform_data(device, "optix motion transform", false) { } diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp index 44a51835f4c..5b62292ca55 100644 --- a/intern/cycles/device/cuda/device_cuda_impl.cpp +++ b/intern/cycles/device/cuda/device_cuda_impl.cpp @@ -854,7 +854,7 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_ void *shared_pointer = 0; - if (mem_alloc_result != CUDA_SUCCESS && can_map_host) { + if (mem_alloc_result != CUDA_SUCCESS && can_map_host && mem.type != MEM_DEVICE_ONLY) { if (mem.shared_pointer) { /* Another device already allocated host memory. */ mem_alloc_result = CUDA_SUCCESS; @@ -877,8 +877,14 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_ } if (mem_alloc_result != CUDA_SUCCESS) { - status = " failed, out of device and host memory"; - set_error("System is out of GPU and shared host memory"); + if (mem.type == MEM_DEVICE_ONLY) { + status = " failed, out of device memory"; + set_error("System is out of GPU memory"); + } + else { + status = " failed, out of device and host memory"; + set_error("System is out of GPU and shared host memory"); + } } if (mem.name) { diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index fdfd3f83be6..e2f9c7391da 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -396,8 +396,7 @@ class CPUDevice : public Device { << string_human_readable_size(mem.memory_size()) << ")"; } - if (mem.type == MEM_DEVICE_ONLY) { - assert(!mem.host_pointer); + if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) { size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES; void *data = util_aligned_malloc(mem.memory_size(), alignment); mem.device_pointer = (device_ptr)data; @@ -459,7 +458,7 @@ class CPUDevice : public Device { tex_free((device_texture &)mem); } else if (mem.device_pointer) { - if (mem.type == MEM_DEVICE_ONLY) { + if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) { util_aligned_free((void *)mem.device_pointer); } mem.device_pointer = 0; diff --git a/intern/cycles/device/device_denoising.h b/intern/cycles/device/device_denoising.h index 2c0dc23b44a..bb8bdfdd225 100644 --- a/intern/cycles/device/device_denoising.h +++ b/intern/cycles/device/device_denoising.h @@ -171,7 +171,8 @@ class DenoisingTask { bool gpu_temporary_mem; DenoiseBuffers(Device *device) - : mem(device, "denoising pixel buffer"), temporary_mem(device, "denoising temporary mem") + : mem(device, "denoising pixel buffer"), + temporary_mem(device, "denoising temporary mem", true) { } } buffer; diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 1f63a152458..97459b9ae6a 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -270,8 +270,8 @@ class device_memory { template class device_only_memory : public device_memory { public: - device_only_memory(Device *device, const char *name) - : device_memory(device, name, MEM_DEVICE_ONLY) + device_only_memory(Device *device, const char *name, bool allow_host_memory_fallback = false) + : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY) { data_type = device_type_traits::data_type; data_elements = max(device_type_traits::num_elements, 1); diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 07ce63f5394..51e1a0033ba 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -197,8 +197,8 @@ class OptiXDevice : public CUDADevice { OptiXDevice(DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool background_) : CUDADevice(info_, stats_, profiler_, background_), sbt_data(this, "__sbt", MEM_READ_ONLY), - launch_params(this, "__params"), - denoiser_state(this, "__denoiser_state") + launch_params(this, "__params", false), + denoiser_state(this, "__denoiser_state", true) { // Store number of CUDA streams in device info info.cpu_threads = DebugFlags().optix.cuda_streams; @@ -878,8 +878,8 @@ class OptiXDevice : public CUDADevice { device_ptr input_ptr = rtile.buffer + pixel_offset; // Copy tile data into a common buffer if necessary - device_only_memory input(this, "denoiser input"); - device_vector tile_info_mem(this, "denoiser tile info", MEM_READ_WRITE); + device_only_memory input(this, "denoiser input", true); + device_vector tile_info_mem(this, "denoiser tile info", MEM_READ_ONLY); bool contiguous_memory = true; for (int i = 0; i < RenderTileNeighbors::SIZE; i++) { @@ -924,7 +924,7 @@ class OptiXDevice : public CUDADevice { } # if OPTIX_DENOISER_NO_PIXEL_STRIDE - device_only_memory input_rgb(this, "denoiser input rgb"); + device_only_memory input_rgb(this, "denoiser input rgb", true); input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.input_passes); void *input_args[] = {&input_rgb.device_pointer, @@ -1146,6 +1146,13 @@ class OptiXDevice : public CUDADevice { const OptixBuildInput &build_input, uint16_t num_motion_steps) { + /* Allocate and build acceleration structures only one at a time, to prevent parallel builds + * from running out of memory (since both original and compacted acceleration structure memory + * may be allocated at the same time for the duration of this function). The builds would + * otherwise happen on the same CUDA stream anyway. */ + static thread_mutex mutex; + thread_scoped_lock lock(mutex); + const CUDAContextScope scope(cuContext); // Compute memory usage @@ -1170,11 +1177,12 @@ class OptiXDevice : public CUDADevice { optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes)); // Allocate required output buffers - device_only_memory temp_mem(this, "optix temp as build mem"); + device_only_memory temp_mem(this, "optix temp as build mem", true); temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8); if (!temp_mem.device_pointer) return false; // Make sure temporary memory allocation succeeded + // Acceleration structure memory has to be allocated on the device (not allowed to be on host) device_only_memory &out_data = bvh->as_data; if (operation == OPTIX_BUILD_OPERATION_BUILD) { assert(out_data.device == this); @@ -1222,7 +1230,7 @@ class OptiXDevice : public CUDADevice { // There is no point compacting if the size does not change if (compacted_size < sizes.outputSizeInBytes) { - device_only_memory compacted_data(this, "optix compacted as"); + device_only_memory compacted_data(this, "optix compacted as", false); compacted_data.alloc_to_device(compacted_size); if (!compacted_data.device_pointer) // Do not compact if memory allocation for compacted acceleration structure fails @@ -1242,6 +1250,7 @@ class OptiXDevice : public CUDADevice { std::swap(out_data.device_size, compacted_data.device_size); std::swap(out_data.device_pointer, compacted_data.device_pointer); + // Original acceleration structure memory is freed when 'compacted_data' goes out of scope } } -- cgit v1.2.3 From 0a6ed7f0352dc0af7e189f5c59bd999d9e83fa30 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Mar 2021 08:37:51 +0100 Subject: LibOverride: Add a utils to check if override has been user-edited. Part of T83811 & D10649. --- source/blender/blenkernel/BKE_lib_override.h | 2 ++ source/blender/blenkernel/intern/lib_override.c | 28 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 5fd451dc986..19109d67114 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -61,6 +61,8 @@ void BKE_lib_override_library_copy(struct ID *dst_id, void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user); void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user); +bool BKE_lib_override_library_is_user_edited(struct ID *id); + struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, struct ID *reference_id, const bool do_tagged_remap); diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 702d718f2b9..40699f41275 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -217,6 +217,32 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id) return local_id; } +/** Check if given ID has some override rules that actually indicate the user edited it. + * + * TODO: This could be simplified by storing a flag in IDOverrideLibrary during the diffing + * process? */ +bool BKE_lib_override_library_is_user_edited(struct ID *id) +{ + if (!ID_IS_OVERRIDE_LIBRARY(id)) { + return false; + } + + LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) { + LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) { + if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) { + continue; + } + if (opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) { + continue; + } + /* If an operation does not match the filters above, it is considered as a user-editing one, + * therefore this override is user-edited. */ + return true; + } + } + return false; +} + /** Create an overridden local copy of linked reference. */ ID *BKE_lib_override_library_create_from_id(Main *bmain, ID *reference_id, @@ -383,7 +409,7 @@ typedef struct LibOverrideGroupTagData { * * Requires existing `Main.relations`. * - * Note: this is typically called to complete `lib_override_linked_group_tag()`. + * NOTE: This is typically called to complete `lib_override_linked_group_tag()`. */ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTagData *data) { -- cgit v1.2.3 From 96064c3bb7d135ab69eb4a146c173dc4a36db1cc Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Mar 2021 09:12:40 +0100 Subject: LibOverride: Do not delete no-more-used overrides during resync if they are user-edited. Ultimately those will be listed with a special icon in the upcomming Outliner overrides view. Part of T83811 & D10649. --- source/blender/blenkernel/intern/lib_override.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 40699f41275..95643773088 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1001,11 +1001,23 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ } id->tag &= ~LIB_TAG_DOIT; } - /* Also cleanup old overrides that went missing in new linked data. */ + /* Also deal with old overrides that went missing in new linked data. */ else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) { BLI_assert(ID_IS_OVERRIDE_LIBRARY(id)); - id->tag |= LIB_TAG_DOIT; - id->tag &= ~LIB_TAG_MISSING; + if (!BKE_lib_override_library_is_user_edited(id)) { + /* If user never edited them, we can delete them. */ + id->tag |= LIB_TAG_DOIT; + id->tag &= ~LIB_TAG_MISSING; + printf("%s: Old override %s is being deleted.\n", __func__, id->name); + } + else { + /* Otherwise, keep them, user needs to decide whether what to do with them. */ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + id_fake_user_set(id); + printf("%s: Old override %s is being kept around as it was user-edited.\n", + __func__, + id->name); + } } } FOREACH_MAIN_ID_END; -- cgit v1.2.3 From 534f4e90fd62dab3a19228219c69cb3f065c6f43 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 31 Dec 2020 18:03:45 +0100 Subject: LibOverride: First stage of detection of 'need resync'. We can fairly easily detect some resync-needed cases when applying the overrides operations on a Pointer RNA property. This should cover all cases where an existing override's ID pointer is changed in its linked data. We still have to add code to detect when a not-yet-overridden linked ID needs to become overridden (because its relations to other data-blocks changed in a way that requires it). Part of T83811 & D10649. --- source/blender/blenkernel/intern/lib_override.c | 14 ++++++-- source/blender/makesdna/DNA_ID.h | 4 +++ .../makesrna/intern/rna_access_compare_override.c | 39 +++++++++++++++++++--- source/blender/makesrna/intern/rna_rna.c | 17 ++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 95643773088..b9158697df9 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -909,6 +909,8 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ ID *id_override_new = id->newid; ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0); + if (id_override_old != NULL) { /* Swap the names between old override ID and new one. */ char id_name_buf[MAX_ID_NAME]; @@ -1920,6 +1922,14 @@ void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain) FOREACH_MAIN_ID_END; } +static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp) +{ + BKE_lib_id_swap(bmain, id_local, id_temp); + /* We need to keep these tags from temp ID into orig one. + * ID swap does not swap most of ID data itself. */ + id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC); +} + /** Update given override from its reference (re-applying overridden properties). */ void BKE_lib_override_library_update(Main *bmain, ID *local) { @@ -1988,11 +1998,11 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. * So when we'll free tmp_id, we'll actually free old, outdated data from local. */ - BKE_lib_id_swap(bmain, local, tmp_id); + lib_override_id_swap(bmain, local, tmp_id); if (local_key != NULL && tmp_key != NULL) { /* This is some kind of hard-coded 'always enforced override'. */ - BKE_lib_id_swap(bmain, &local_key->id, &tmp_key->id); + lib_override_id_swap(bmain, &local_key->id, &tmp_key->id); tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE); /* The swap of local and tmp_id inverted those pointers, we need to redefine proper * relationships. */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index c708219cfe8..077f9bf8bdc 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -572,6 +572,10 @@ enum { * When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */ LIB_TAG_TEMP_MAIN = 1 << 20, + /** + * The data-block is a library override that needs re-sync to its linked reference. + */ + LIB_TAG_LIB_OVERRIDE_NEED_RESYNC = 1 << 21, }; /* Tag given ID for an update in all the dependency graphs. */ diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 0f3b0a895db..6a8152d1139 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -61,7 +61,7 @@ static CLG_LogRef LOG = {"rna.access_compare_override"}; * Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the * full rna path from it to given \a prop #PropertyRNA if \a rna_path is given. * - * \note this is slightly different than 'generic' RNA 'id owner' as returned by + * \note This is slightly different than 'generic' RNA 'id owner' as returned by * #RNA_find_real_ID_and_path, since in overrides we also consider shape keys as embedded data, not * only root node trees and master collections. */ @@ -104,10 +104,6 @@ static ID *rna_property_override_property_real_id_owner(Main *bmain, } } - if (!ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) { - return NULL; - } - if (r_rna_path == NULL) { return owner_id; } @@ -1158,6 +1154,39 @@ void RNA_struct_override_apply(Main *bmain, ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage); } + /* Check if an overridden ID pointer supposed to be in sync with linked data gets out of + * sync. */ + if ((ptr_dst->owner_id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0 && + op->rna_prop_type == PROP_POINTER && + (((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag & + IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) { + BLI_assert(ptr_src->owner_id == + rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL)); + BLI_assert(ptr_dst->owner_id == + rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL)); + + PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src); + PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst); + ID *id_src = rna_property_override_property_real_id_owner( + bmain, &prop_ptr_src, NULL, NULL); + ID *id_dst = rna_property_override_property_real_id_owner( + bmain, &prop_ptr_dst, NULL, NULL); + + BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src)); + + if (/* We might be in a case where id_dst has already been processed and its usages + * remapped to its new local override. In that case overrides and linked data are + * always properly matching. */ + id_src != id_dst && + /* If one of the pointers is NULL and not the other, or if linked reference ID of + * `id_src` is not `id_dst`, we are in a non-matching case. */ + (ELEM(NULL, id_src, id_dst) || id_src->override_library->reference != id_dst)) { + ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; + CLOG_INFO( + &LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name); + } + } + rna_property_override_apply_ex(bmain, &data_dst, &data_src, diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index d553ead1e45..d8336e79064 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1238,6 +1238,8 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop /* Used for both Pointer and Collection properties. */ static int rna_property_override_diff_propptr(Main *bmain, + ID *owner_id_a, + ID *owner_id_b, PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, @@ -1359,6 +1361,17 @@ static int rna_property_override_diff_propptr(Main *bmain, * override is not matching its reference anymore. */ opop->flag &= ~IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE; } + else if ((owner_id_a->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0 || + (owner_id_b->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) != 0) { + /* In case one of the owner of the checked property is tagged as needing resync, do + * not change the 'match reference' status of its ID pointer properties overrides, + * since many non-matching ones are likely due to missing resync. */ + printf( + "%s: Not checking matching ID pointer properties, since owner %s is tagged as " + "needing resync.\n", + __func__, + id_a->name); + } else if (id_a->override_library != NULL && id_a->override_library->reference == id_b) { opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE; } @@ -1778,6 +1791,8 @@ int rna_property_override_diff_default(Main *bmain, PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, rawprop_a); PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, rawprop_b); return rna_property_override_diff_propptr(bmain, + ptr_a->owner_id, + ptr_b->owner_id, &propptr_a, &propptr_b, mode, @@ -1934,6 +1949,8 @@ int rna_property_override_diff_default(Main *bmain, else if (is_id || is_valid_for_diffing) { if (equals || do_create) { const int eq = rna_property_override_diff_propptr(bmain, + ptr_a->owner_id, + ptr_b->owner_id, &iter_a.ptr, &iter_b.ptr, mode, -- cgit v1.2.3 From a023c1a34c43b86a661ce3cc73e8fba72b1bfba4 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Mar 2021 09:16:26 +0100 Subject: LibOverride: Add second part of auto-resync code. `BKE_lib_override_library_main_resync` uses `LIB_TAG_LIB_OVERRIDE_NEED_RESYNC` tags set by RNA override apply code, and perform detection for the remaining cases (those were new overrides need to be created for data that was not present before in the library). And then it actually resync all needed local overrides. Part of T83811 & D10649. --- source/blender/blenkernel/BKE_lib_override.h | 4 + source/blender/blenkernel/intern/lib_override.c | 119 +++++++++++++++++++++++- 2 files changed, 119 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 19109d67114..e548f778c71 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -80,6 +80,10 @@ bool BKE_lib_override_library_resync(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct ID *id_root); +void BKE_lib_override_library_main_resync(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer); + void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root); struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find( diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index b9158697df9..5100fbf08ad 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1010,15 +1010,13 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ /* If user never edited them, we can delete them. */ id->tag |= LIB_TAG_DOIT; id->tag &= ~LIB_TAG_MISSING; - printf("%s: Old override %s is being deleted.\n", __func__, id->name); + CLOG_INFO(&LOG, 3, "Old override %s is being deleted", id->name); } else { /* Otherwise, keep them, user needs to decide whether what to do with them. */ BLI_assert((id->tag & LIB_TAG_DOIT) == 0); id_fake_user_set(id); - printf("%s: Old override %s is being kept around as it was user-edited.\n", - __func__, - id->name); + CLOG_INFO(&LOG, 3, "Old override %s is being kept around as it was user-edited", id->name); } } } @@ -1046,6 +1044,119 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ return success; } +/** + * Detect and handle required resync of overrides data, when relations between reference linked IDs + * have changed. + * + * This is a fairly complex and costly operation, typically it should be called after + * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases. + * + * This function will first detect the remaining cases requiring a resync (namely, either when an + * existing linked ID that did not require to be overridden before now would be, or when new IDs + * are added to the hierarchy). + * + * Then it will handle the resync of necessary IDs (through calls to + * #BKE_lib_override_library_resync). + */ +void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *view_layer) +{ + BKE_main_relations_create(bmain, 0); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* NOTE: in code below, the order in which `FOREACH_MAIN_ID_BEGIN` processes ID types ensures + * that we always process 'higher-level' overrides first (i.e. scenes, then collections, then + * objects, then other types). */ + + /* Detect all linked data that would need to be overridden if we had to create an override from + * those used by current existing overrides. */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + continue; + } + if (id->tag & (LIB_TAG_DOIT | LIB_TAG_MISSING)) { + /* We already processed that ID as part of another ID's hierarchy. */ + continue; + } + + LibOverrideGroupTagData data = {.bmain = bmain, + .id_root = id->override_library->reference, + .tag = LIB_TAG_DOIT, + .missing_tag = LIB_TAG_MISSING}; + lib_override_linked_group_tag(&data); + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); + lib_override_hierarchy_dependencies_recursive_tag(&data); + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); + } + FOREACH_MAIN_ID_END; + + /* Now check existing overrides, those needing resync will be the one either already tagged as + * such, or the one using linked data that is now tagged as needing override. */ + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + continue; + } + + if (id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) { + CLOG_INFO(&LOG, 4, "ID %s was already tagged as needing resync", id->name); + continue; + } + + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id); + BLI_assert(entry != NULL); + + for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL; + entry_item = entry_item->next) { + if (entry_item->usage_flag & + (IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + continue; + } + ID *id_to = *entry_item->id_pointer.to; + + /* Case where this ID pointer was to a linked ID, that now needs to be overridden. */ + if (ID_IS_LINKED(id_to) && (id_to->tag & LIB_TAG_DOIT) != 0) { + id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; + CLOG_INFO(&LOG, + 3, + "ID %s now tagged as needing resync because they use linked %s that now needs " + "to be overridden", + id->name, + id_to->name); + break; + } + } + } + FOREACH_MAIN_ID_END; + + BKE_main_relations_free(bmain); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* And do the actual resync for all IDs detected as needing it. + * NOTE: Since this changes `bmain` (adding **and** removing IDs), we cannot use + * `FOREACH_MAIN_ID_BEGIN/END` here, and need special multi-loop processing. */ + bool do_continue = true; + while (do_continue) { + ListBase *lb; + do_continue = false; + FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) { + FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) { + if ((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0) { + continue; + } + do_continue = true; + const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id); + CLOG_INFO(&LOG, 2, "Resynced %s, success: %d", id->name, success); + break; + } + FOREACH_MAIN_LISTBASE_ID_END; + if (do_continue) { + break; + } + } + FOREACH_MAIN_LISTBASE_END; + } +} + /** * Advanced 'smart' function to delete library overrides (including their existing override * hierarchy) and remap their usages to their linked reference IDs. -- cgit v1.2.3 From 93f8c9b8238b4f69c34b605b7e08dfe113f4023d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 5 Mar 2021 09:21:12 +0100 Subject: LibOverride: auto-run resync process on file reading. Part of T83811 & D10649. --- source/blender/blenkernel/intern/blendfile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 101f4b7caf6..a7af0eccb49 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -51,6 +51,7 @@ #include "BKE_keyconfig.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_preferences.h" #include "BKE_report.h" @@ -401,6 +402,13 @@ static void setup_app_data(bContext *C, * to recompute refcount for all local IDs too. */ BKE_main_id_refcount_recompute(bmain, false); } + + if (mode != LOAD_UNDO) { + BKE_lib_override_library_main_resync( + bmain, + curscene, + bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene)); + } } static void setup_app_blend_file_data(bContext *C, -- cgit v1.2.3 From f7616c6eaf8d983e84aeb838d51fe67e4fa98e16 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 00:34:19 +1100 Subject: Cleanup: file loading/recover checks - Don't set G.relbase_valid until the file is loaded. - Remove unnecessary string pointer comparison. - Remove unused filename being passed to 'setup_app_data'. --- source/blender/blenkernel/intern/blendfile.c | 23 +++++++---------------- source/blender/windowmanager/intern/wm_files.c | 5 ++--- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index a7af0eccb49..c3edd84fd43 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -132,11 +132,9 @@ static void setup_app_userdef(BlendFileData *bfd) * should be avoided or check (mode != LOAD_UNDO). * * \param bfd: Blend file data, freed by this function on exit. - * \param filepath: File path or identifier. */ static void setup_app_data(bContext *C, BlendFileData *bfd, - const char *filepath, const struct BlendFileReadParams *params, ReportList *reports) { @@ -350,16 +348,10 @@ static void setup_app_data(bContext *C, if (is_startup) { bmain->name[0] = '\0'; } - else if (recover && G.relbase_valid) { - /* in case of autosave or quit.blend, use original filename instead - * use relbase_valid to make sure the file is saved, else we get in the filename */ - filepath = bfd->filename; + else if (recover) { + /* In case of autosave or quit.blend, use original filename instead. */ bmain->recovered = 1; - - /* these are the same at times, should never copy to the same location */ - if (bmain->name != filepath) { - BLI_strncpy(bmain->name, filepath, FILE_MAX); - } + BLI_strncpy(bmain->name, bfd->filename, FILE_MAX); } /* baseflags, groups, make depsgraph, etc */ @@ -413,7 +405,6 @@ static void setup_app_data(bContext *C, static void setup_app_blend_file_data(bContext *C, BlendFileData *bfd, - const char *filepath, const struct BlendFileReadParams *params, ReportList *reports) { @@ -421,7 +412,7 @@ static void setup_app_blend_file_data(bContext *C, setup_app_userdef(bfd); } if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { - setup_app_data(C, bfd, filepath, params, reports); + setup_app_data(C, bfd, params, reports); } } @@ -460,7 +451,7 @@ bool BKE_blendfile_read_ex(bContext *C, BLO_update_defaults_startup_blend(bfd->main, startup_app_template); } } - setup_app_blend_file_data(C, bfd, filepath, params, reports); + setup_app_blend_file_data(C, bfd, params, reports); BLO_blendfiledata_free(bfd); } else { @@ -493,7 +484,7 @@ bool BKE_blendfile_read_from_memory_ex(bContext *C, BLO_update_defaults_startup_blend(bfd->main, startup_app_template); } } - setup_app_blend_file_data(C, bfd, "", params, reports); + setup_app_blend_file_data(C, bfd, params, reports); BLO_blendfiledata_free(bfd); } else { @@ -529,7 +520,7 @@ bool BKE_blendfile_read_from_memfile(bContext *C, BLI_assert(BLI_listbase_is_empty(&bfd->main->workspaces)); BLI_assert(BLI_listbase_is_empty(&bfd->main->screens)); - setup_app_blend_file_data(C, bfd, "", params, reports); + setup_app_blend_file_data(C, bfd, params, reports); BLO_blendfiledata_free(bfd); } else { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 13f3afdfc4c..8a8baad0df0 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -729,8 +729,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* also exit screens and editors */ wm_window_match_init(C, &wmbase); - /* confusing this global... */ - G.relbase_valid = 1; success = BKE_blendfile_read( C, filepath, @@ -746,9 +744,10 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* BKE_file_read sets new Main into context. */ Main *bmain = CTX_data_main(C); - /* when loading startup.blend's, we can be left with a blank path */ + /* When recovering a session from an unsaved file, this can have a blank path. */ if (BKE_main_blendfile_path(bmain)[0] != '\0') { G.save_over = 1; + G.relbase_valid = 1; } else { G.save_over = 0; -- cgit v1.2.3 From 5812bc7d8908015b8a06d240da7964be0a19a2c3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 00:34:21 +1100 Subject: Cleanup: split file read and setup into separate steps Currently file loading performs almost all reloading logic even in the case loading the file fails, causing the file to be in a state that isn't well defined: undo is cleared, timers are canceled & scripts are re-registered. --- source/blender/blenkernel/BKE_blendfile.h | 53 ++++++----- source/blender/blenkernel/intern/blender_undo.c | 14 ++- source/blender/blenkernel/intern/blendfile.c | 115 ++++++++++++------------ source/blender/windowmanager/intern/wm_files.c | 64 ++++++------- 4 files changed, 128 insertions(+), 118 deletions(-) diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index f73c4a70809..429e294a337 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -23,6 +23,7 @@ extern "C" { #endif +struct BlendFileData; struct BlendFileReadParams; struct ID; struct Main; @@ -31,36 +32,32 @@ struct ReportList; struct UserDef; struct bContext; -bool BKE_blendfile_read_ex(struct bContext *C, - const char *filepath, - const struct BlendFileReadParams *params, - struct ReportList *reports, - /* Extra args. */ - const bool startup_update_defaults, - const char *startup_app_template); -bool BKE_blendfile_read(struct bContext *C, - const char *filepath, - const struct BlendFileReadParams *params, - struct ReportList *reports); +void BKE_blendfile_read_setup_ex(struct bContext *C, + struct BlendFileData *bfd, + const struct BlendFileReadParams *params, + struct ReportList *reports, + /* Extra args. */ + const bool startup_update_defaults, + const char *startup_app_template); -bool BKE_blendfile_read_from_memory_ex(struct bContext *C, - const void *filebuf, - int filelength, - const struct BlendFileReadParams *params, - struct ReportList *reports, - /* Extra args. */ - const bool startup_update_defaults, - const char *startup_app_template); -bool BKE_blendfile_read_from_memory(struct bContext *C, - const void *filebuf, - int filelength, - const struct BlendFileReadParams *params, - struct ReportList *reports); +void BKE_blendfile_read_setup(struct bContext *C, + struct BlendFileData *bfd, + const struct BlendFileReadParams *params, + struct ReportList *reports); -bool BKE_blendfile_read_from_memfile(struct bContext *C, - struct MemFile *memfile, - const struct BlendFileReadParams *params, - struct ReportList *reports); +struct BlendFileData *BKE_blendfile_read(const char *filepath, + const struct BlendFileReadParams *params, + struct ReportList *reports); + +struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf, + int filelength, + const struct BlendFileReadParams *params, + struct ReportList *reports); + +struct BlendFileData *BKE_blendfile_read_from_memfile(struct Main *bmain, + struct MemFile *memfile, + const struct BlendFileReadParams *params, + struct ReportList *reports); void BKE_blendfile_read_make_empty(struct bContext *C); struct UserDef *BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports); diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index d826aaf24e3..9f8a30722c2 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -77,7 +77,12 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, G.fileflags |= G_FILE_NO_UI; if (UNDO_DISK) { - success = BKE_blendfile_read(C, mfu->filename, &(const struct BlendFileReadParams){0}, NULL); + const struct BlendFileReadParams params = {0}; + struct BlendFileData *bfd = BKE_blendfile_read(mfu->filename, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup(C, bfd, ¶ms, NULL); + success = true; + } } else { struct BlendFileReadParams params = {0}; @@ -85,7 +90,12 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, if (!use_old_bmain_data) { params.skip_flags |= BLO_READ_SKIP_UNDO_OLD_MAIN; } - success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, ¶ms, NULL); + struct BlendFileData *bfd = BKE_blendfile_read_from_memfile( + bmain, &mfu->memfile, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup(C, bfd, ¶ms, NULL); + success = true; + } } /* Restore, bmain has been re-allocated. */ diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index c3edd84fd43..d3dfe60c444 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -429,15 +429,46 @@ static void handle_subversion_warning(Main *main, ReportList *reports) } } -bool BKE_blendfile_read_ex(bContext *C, - const char *filepath, - const struct BlendFileReadParams *params, - ReportList *reports, - /* Extra args. */ - const bool startup_update_defaults, - const char *startup_app_template) +/** + * Shared setup function that makes the data from `bfd` into the current blend file, + * replacing the contents of #G.main. + * This uses the bfd #BKE_blendfile_read and similarly named functions. + * + * This is done in a separate step so the caller may perform actions after it is known the file + * loaded correctly but before the file replaces the existing blend file contents. + */ +void BKE_blendfile_read_setup_ex(bContext *C, + BlendFileData *bfd, + const struct BlendFileReadParams *params, + ReportList *reports, + /* Extra args. */ + const bool startup_update_defaults, + const char *startup_app_template) { + if (startup_update_defaults) { + if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { + BLO_update_defaults_startup_blend(bfd->main, startup_app_template); + } + } + setup_app_blend_file_data(C, bfd, params, reports); + BLO_blendfiledata_free(bfd); +} +void BKE_blendfile_read_setup(bContext *C, + BlendFileData *bfd, + const struct BlendFileReadParams *params, + ReportList *reports) +{ + BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL); +} + +/** + * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL. + */ +struct BlendFileData *BKE_blendfile_read(const char *filepath, + const struct BlendFileReadParams *params, + ReportList *reports) +{ /* Don't print startup file loading. */ if (params->is_startup == false) { printf("Read blend: %s\n", filepath); @@ -446,69 +477,40 @@ bool BKE_blendfile_read_ex(bContext *C, BlendFileData *bfd = BLO_read_from_file(filepath, params->skip_flags, reports); if (bfd) { handle_subversion_warning(bfd->main, reports); - if (startup_update_defaults) { - if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { - BLO_update_defaults_startup_blend(bfd->main, startup_app_template); - } - } - setup_app_blend_file_data(C, bfd, params, reports); - BLO_blendfiledata_free(bfd); } else { BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath); } - return (bfd != NULL); + return bfd; } -bool BKE_blendfile_read(bContext *C, - const char *filepath, - const struct BlendFileReadParams *params, - ReportList *reports) -{ - return BKE_blendfile_read_ex(C, filepath, params, reports, false, NULL); -} - -bool BKE_blendfile_read_from_memory_ex(bContext *C, - const void *filebuf, - int filelength, - const struct BlendFileReadParams *params, - ReportList *reports, - /* Extra args. */ - const bool startup_update_defaults, - const char *startup_app_template) +/** + * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL. + */ +struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf, + int filelength, + const struct BlendFileReadParams *params, + ReportList *reports) { BlendFileData *bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports); if (bfd) { - if (startup_update_defaults) { - if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { - BLO_update_defaults_startup_blend(bfd->main, startup_app_template); - } - } - setup_app_blend_file_data(C, bfd, params, reports); - BLO_blendfiledata_free(bfd); + /* Pass. */ } else { BKE_reports_prepend(reports, "Loading failed: "); } - return (bfd != NULL); + return bfd; } -bool BKE_blendfile_read_from_memory(bContext *C, - const void *filebuf, - int filelength, - const struct BlendFileReadParams *params, - ReportList *reports) -{ - return BKE_blendfile_read_from_memory_ex(C, filebuf, filelength, params, reports, false, NULL); -} - -/* memfile is the undo buffer */ -bool BKE_blendfile_read_from_memfile(bContext *C, - struct MemFile *memfile, - const struct BlendFileReadParams *params, - ReportList *reports) +/** + * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL. + * \note `memfile` is the undo buffer. + */ +struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain, + struct MemFile *memfile, + const struct BlendFileReadParams *params, + ReportList *reports) { - Main *bmain = CTX_data_main(C); BlendFileData *bfd = BLO_read_from_memfile( bmain, BKE_main_blendfile_path(bmain), memfile, params, reports); if (bfd) { @@ -519,14 +521,11 @@ bool BKE_blendfile_read_from_memfile(bContext *C, BLI_assert(BLI_listbase_is_empty(&bfd->main->wm)); BLI_assert(BLI_listbase_is_empty(&bfd->main->workspaces)); BLI_assert(BLI_listbase_is_empty(&bfd->main->screens)); - - setup_app_blend_file_data(C, bfd, params, reports); - BLO_blendfiledata_free(bfd); } else { BKE_reports_prepend(reports, "Loading failed: "); } - return (bfd != NULL); + return bfd; } /** diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 8a8baad0df0..3bf925af2ce 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -729,17 +729,19 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* also exit screens and editors */ wm_window_match_init(C, &wmbase); - success = BKE_blendfile_read( - C, - filepath, - /* Loading preferences when the user intended to load a regular file is a security risk, - * because the excluded path list is also loaded. - * Further it's just confusing if a user loads a file and various preferences change. */ - &(const struct BlendFileReadParams){ - .is_startup = false, - .skip_flags = BLO_READ_SKIP_USERDEF, - }, - reports); + const struct BlendFileReadParams params = { + .is_startup = false, + /* Loading preferences when the user intended to load a regular file is a security + * risk, because the excluded path list is also loaded. Further it's just confusing + * if a user loads a file and various preferences change. */ + .skip_flags = BLO_READ_SKIP_USERDEF, + }; + + struct BlendFileData *bfd = BKE_blendfile_read(filepath, ¶ms, reports); + if (bfd != NULL) { + BKE_blendfile_read_setup(C, bfd, ¶ms, reports); + success = true; + } /* BKE_file_read sets new Main into context. */ Main *bmain = CTX_data_main(C); @@ -1040,15 +1042,17 @@ void wm_homefile_read(bContext *C, if (!use_factory_settings || (filepath_startup[0] != '\0')) { if (BLI_access(filepath_startup, R_OK) == 0) { - success = BKE_blendfile_read_ex(C, - filepath_startup, - &(const struct BlendFileReadParams){ - .is_startup = true, - .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF, - }, - NULL, - update_defaults && use_data, - app_template); + const struct BlendFileReadParams params = { + .is_startup = true, + .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF, + }; + + struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup_ex( + C, bfd, ¶ms, NULL, update_defaults && use_data, app_template); + success = true; + } } if (success) { is_factory_startup = filepath_startup_is_factory; @@ -1069,16 +1073,16 @@ void wm_homefile_read(bContext *C, } if (success == false) { - success = BKE_blendfile_read_from_memory_ex(C, - datatoc_startup_blend, - datatoc_startup_blend_size, - &(const struct BlendFileReadParams){ - .is_startup = true, - .skip_flags = skip_flags, - }, - NULL, - true, - NULL); + const struct BlendFileReadParams params = { + .is_startup = true, + .skip_flags = skip_flags, + }; + struct BlendFileData *bfd = BKE_blendfile_read_from_memory( + datatoc_startup_blend, datatoc_startup_blend_size, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup_ex(C, bfd, ¶ms, NULL, true, NULL); + success = true; + } if (use_data && BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); -- cgit v1.2.3 From 2cdebf293d4cf925e1cdaf5c4a247b8886c1026e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 00:34:23 +1100 Subject: WM: keep the current state when a blend fails to load Previously many operations would run on file load, even if the file did not load. Pre/post load handlers were called, timers canceled, all undo data freed, editors exited ... etc. Now keep the blend file in it's current state. This simplifies updating this area of code as there is one less possible situation to account for. --- source/blender/windowmanager/intern/wm_files.c | 72 +++++++++++++------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 3bf925af2ce..2d1342da2fb 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -713,8 +713,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_cursor_wait(true); - wm_file_read_pre(C, use_data, use_userdef); - /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ @@ -722,13 +720,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { - const int G_f_orig = G.f; - ListBase wmbase; - - /* put aside screens to match with persistent windows later */ - /* also exit screens and editors */ - wm_window_match_init(C, &wmbase); - const struct BlendFileReadParams params = { .is_startup = false, /* Loading preferences when the user intended to load a regular file is a security @@ -739,42 +730,50 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) struct BlendFileData *bfd = BKE_blendfile_read(filepath, ¶ms, reports); if (bfd != NULL) { + wm_file_read_pre(C, use_data, use_userdef); + + /* Put aside screens to match with persistent windows later, + * also exit screens and editors. */ + ListBase wmbase; + wm_window_match_init(C, &wmbase); + + /* This flag is initialized by the operator but overwritten on read. + * need to re-enable it here else drivers + registered scripts wont work. */ + const int G_f_orig = G.f; + BKE_blendfile_read_setup(C, bfd, ¶ms, reports); - success = true; - } - /* BKE_file_read sets new Main into context. */ - Main *bmain = CTX_data_main(C); + if (G.f != G_f_orig) { + const int flags_keep = G_FLAG_ALL_RUNTIME; + G.f &= G_FLAG_ALL_READFILE; + G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep); + } - /* When recovering a session from an unsaved file, this can have a blank path. */ - if (BKE_main_blendfile_path(bmain)[0] != '\0') { - G.save_over = 1; - G.relbase_valid = 1; - } - else { - G.save_over = 0; - G.relbase_valid = 0; - } + /* #BKE_blendfile_read_result_setup sets new Main into context. */ + Main *bmain = CTX_data_main(C); - /* this flag is initialized by the operator but overwritten on read. - * need to re-enable it here else drivers + registered scripts wont work. */ - if (G.f != G_f_orig) { - const int flags_keep = G_FLAG_ALL_RUNTIME; - G.f &= G_FLAG_ALL_READFILE; - G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep); - } + /* When recovering a session from an unsaved file, this can have a blank path. */ + if (BKE_main_blendfile_path(bmain)[0] != '\0') { + G.save_over = 1; + G.relbase_valid = 1; + } + else { + G.save_over = 0; + G.relbase_valid = 0; + } - /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); - WM_check(C); /* opens window(s), checks keymaps */ + /* match the read WM with current WM */ + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); + WM_check(C); /* opens window(s), checks keymaps */ - if (success) { if (do_history_file_update) { wm_history_file_update(); } - } - wm_file_read_post(C, false, false, use_data, use_userdef, false); + wm_file_read_post(C, false, false, use_data, use_userdef, false); + + success = true; + } } #if 0 else if (retval == BKE_READ_EXOTIC_OK_OTHER) { @@ -951,6 +950,9 @@ void wm_homefile_read(bContext *C, #endif /* WITH_PYTHON */ } + /* For regular file loading this only runs after the file is successfully read. + * In the case of the startup file, the in-memory startup file is used as a fallback + * so we know this will work if all else fails. */ wm_file_read_pre(C, use_data, use_userdef); if (use_data) { -- cgit v1.2.3 From 2cc5af9c553cfc00b7d4616445ad954597a92d94 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 00:34:23 +1100 Subject: Fix T86431: Keep memory location of the window manager on file load Keep the pointer location from the initial window-manager between file load operations. This is needed as the Python API may hold references to keymaps for e.g. which are transferred to the newly loaded window manager, without their `PointerRNA.owner_id` fields being updated. Since there is only ever one window manager, keep the memory at the same location so the Python ID pointers stay valid. Reviewed By: mont29 Ref D10690 --- source/blender/blenkernel/BKE_lib_remap.h | 2 ++ source/blender/blenkernel/intern/lib_remap.c | 32 +++++++++++++++----------- source/blender/windowmanager/intern/wm_files.c | 24 +++++++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index a8d75213d39..6e81273b82b 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -76,6 +76,8 @@ enum { ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4, /** Do not remap library override pointers. */ ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5, + /** Don't touch the user count (use for low level actions such as swapping pointers). */ + ID_REMAP_SKIP_USER_CLEAR = 1 << 6, }; /* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 56f7bb0be6f..0218cb913a8 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -422,15 +422,17 @@ static void libblock_remap_data( FOREACH_MAIN_ID_END; } - /* XXX We may not want to always 'transfer' fake-user from old to new id... - * Think for now it's desired behavior though, - * we can always add an option (flag) to control this later if needed. */ - if (old_id && (old_id->flag & LIB_FAKEUSER)) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } + if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) { + /* XXX We may not want to always 'transfer' fake-user from old to new id... + * Think for now it's desired behavior though, + * we can always add an option (flag) to control this later if needed. */ + if (old_id && (old_id->flag & LIB_FAKEUSER)) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } - id_us_clear_real(old_id); + id_us_clear_real(old_id); + } if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { @@ -479,12 +481,14 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const skipped_direct = id_remap_data.skipped_direct; skipped_refcounted = id_remap_data.skipped_refcounted; - /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user - * count has actually been incremented for that, we have to decrease once more its user count... - * unless we had to skip some 'user_one' cases. */ - if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && - !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { - id_us_clear_real(old_id); + if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) { + /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user + * count has actually been incremented for that, we have to decrease once more its user + * count... unless we had to skip some 'user_one' cases. */ + if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && + !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { + id_us_clear_real(old_id); + } } if (old_id->us - skipped_refcounted < 0) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 2d1342da2fb..bd220e2ff95 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -81,6 +81,7 @@ #include "BKE_idprop.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -296,6 +297,29 @@ static void wm_window_match_replace_by_file_wm(bContext *C, { wmWindowManager *oldwm = current_wm_list->first; wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */ + + /* Support window-manager ID references being held between file load operations by keeping + * #Main.wm.first memory address in-place, while swapping all of it's contents. + * + * This is needed so items such as key-maps can be held by an add-on, + * without it pointing to invalid memory, see: T86431 */ + { + /* Referencing the window-manager pointer from elsewhere in the file is highly unlikely + * however it's possible with ID-properties & animation-drivers. + * At some point we could check on disallowing this since it doesn't seem practical. */ + Main *bmain = G_MAIN; + BLI_assert(bmain->relations == NULL); + BKE_libblock_remap(bmain, wm, oldwm, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_USER_CLEAR); + + /* Simple pointer swapping step. */ + BLI_remlink(current_wm_list, oldwm); + BLI_remlink(readfile_wm_list, wm); + SWAP(wmWindowManager, *oldwm, *wm); + SWAP(wmWindowManager *, oldwm, wm); + BLI_addhead(current_wm_list, oldwm); + BLI_addhead(readfile_wm_list, wm); + } + bool has_match = false; /* this code could move to setup_appdata */ -- cgit v1.2.3 From 5b91a52944d5d6bcb09ed149612a780055061c21 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 00:46:41 +1100 Subject: Cleanup: spelling --- intern/utfconv/utfconv.h | 24 +++++++++++++--------- .../draw/engines/eevee/eevee_screen_raytrace.c | 4 ++-- .../blender/editors/interface/interface_widgets.c | 4 ++-- .../editors/space_outliner/tree/tree_element.cc | 2 +- source/blender/modifiers/intern/MOD_nodes.cc | 4 ++-- source/blender/windowmanager/intern/wm.c | 2 +- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h index 36dff288966..b4addd72c75 100644 --- a/intern/utfconv/utfconv.h +++ b/intern/utfconv/utfconv.h @@ -32,32 +32,36 @@ extern "C" { /** * Counts how many bytes is required for future utf-8 string using utf-16 * \param string16: pointer to working utf-16 string - * \return How many bytes must be allocated includeng NULL. + * \return How many bytes must be allocated including NULL. */ size_t count_utf_8_from_16(const wchar_t *string16); /** * Counts how many wchar_t (two byte) is required for future utf-16 string using utf-8 * \param string8: pointer to working utf-8 string - * \return How many bytes must be allocated includeng NULL. + * \return How many bytes must be allocated including NULL. */ size_t count_utf_16_from_8(const char *string8); -/** +/* * conv_utf_*** errors */ -#define UTF_ERROR_NULL_IN (1 << 0) /* Error occures when requered parameter is missing*/ -#define UTF_ERROR_ILLCHAR (1 << 1) /* Error if character is in illigal UTF rage*/ -#define UTF_ERROR_SMALL \ - (1 << 2) /* Passed size is to small. It gives legal string with character missing at the end */ -#define UTF_ERROR_ILLSEQ (1 << 3) /* Error if sequence is broken and doesn't finish*/ + +/** Error occurs when required parameter is missing. */ +#define UTF_ERROR_NULL_IN (1 << 0) +/** Error if character is in illegal UTF range. */ +#define UTF_ERROR_ILLCHAR (1 << 1) +/** Passed size is to small. It gives legal string with character missing at the end. */ +#define UTF_ERROR_SMALL (1 << 2) +/** Error if sequence is broken and doesn't finish. */ +#define UTF_ERROR_ILLSEQ (1 << 3) /** * Converts utf-16 string to allocated utf-8 string * \param in16: utf-16 string to convert * \param out8: utf-8 string to string the conversion * \param size8: the allocated size in bytes of out8 - * \return Returns any errors occured during conversion. See the block above, + * \return Returns any errors occurred during conversion. See the block above, */ int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8); @@ -66,7 +70,7 @@ int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8); * \param in8: utf-8 string to convert * \param out16: utf-16 string to string the conversion * \param size16: the allocated size in wchar_t (two byte) of out16 - * \return Returns any errors occured during conversion. See the block above, + * \return Returns any errors occurred during conversion. See the block above, */ int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16); diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 94b0161faf8..f5b4e4d43a5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -139,13 +139,13 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v * * Following Frostbite stochastic SSR. * - * - First pass Trace rays across the depth buffer. The hit position and pdf are + * - First pass Trace rays across the depth buffer. The hit position and PDF are * recorded in a RGBA16F render target for each ray (sample). * * - We down-sample the previous frame color buffer. * * - For each final pixel, we gather neighbors rays and choose a color buffer - * mipmap for each ray using its pdf. (filtered importance sampling) + * mipmap for each ray using its PDF. (filtered importance sampling) * We then evaluate the lighting from the probes and mix the results together. */ DRW_PASS_CREATE(psl->ssr_raytrace, DRW_STATE_WRITE_COLOR); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 26b2c7a9091..0c6be7b1196 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1819,7 +1819,7 @@ static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, cons but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr)); but->ofs = 0; - /* First shorten num-buttons eg, + /* First shorten number-buttons eg, * Translucency: 0.000 * becomes * Trans: 0.000 @@ -3801,7 +3801,7 @@ static void widget_numslider( wtb.draw_inner = false; widgetbase_draw(&wtb, wcol); - /* Add space at either side of the button so text aligns with numbuttons + /* Add space at either side of the button so text aligns with number-buttons * (which have arrow icons). */ if (!(state & UI_STATE_TEXT_INPUT)) { rect->xmax -= toffs; diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 6fe3f341fd3..b0508e10671 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -45,7 +45,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te * it as much as possible for now. Would be nice to entirely get rid of that, no more `void *`. * * Once #outliner_add_element() is sufficiently simplified, it should be replaced by a C++ call. - * It could take the derived type as template paramenter (e.g. #TreeElementAnimData) and use C++ + * It could take the derived type as template parameter (e.g. #TreeElementAnimData) and use C++ * perfect forwarding to pass any data to the type's constructor. * If general Outliner code wants to access the data, they can query that through the derived * element type then. There's no need for `void *` anymore then. diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 877b15f5010..f8242c87bd3 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -331,7 +331,7 @@ class GeometryNodesEvaluator { values.append(this->get_input_from_incoming_link(socket_to_compute, from_socket)); } else { - /* If the same from-socket occures more than once, we make a copy of the first value. This + /* If the same from-socket occurs more than once, we make a copy of the first value. This * can happen when a node linked to a multi-input-socket is muted. */ GMutablePointer value = values[first_occurence]; const CPPType *type = value.type(); @@ -647,7 +647,7 @@ static IDProperty *socket_add_property(IDProperty *settings_prop_group, prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY; - /* Make the group in the ui container group to hold the property's UI settings. */ + /* Make the group in the UI container group to hold the property's UI settings. */ IDProperty *prop_ui_group; { IDPropertyTemplate idprop = {0}; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 836bca98f65..b66544831f1 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -20,7 +20,7 @@ /** \file * \ingroup wm * - * Internal functions for managing UI registrable types (operator, UI and menu types). + * Internal functions for managing UI registerable types (operator, UI and menu types). * * Also Blender's main event loop (WM_main). */ -- cgit v1.2.3 From d518b0fda5c1279fe2e2600ccadc431eff6c2e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Thu, 11 Mar 2021 16:09:30 +0100 Subject: Fluid: Updated hidden symbol visibility comment It turns out that on official arm64 devices (not DevKit) the linker warnings still show up. So just leaving this as is. Ref D9002 --- extern/mantaflow/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt index 3220a45bef4..9b047eb1a3e 100644 --- a/extern/mantaflow/CMakeLists.txt +++ b/extern/mantaflow/CMakeLists.txt @@ -32,9 +32,7 @@ if(MSVC_CLANG AND WITH_OPENMP AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.1 endif() # Exporting functions from the blender binary gives linker warnings on Apple arm64 systems. -# For now and until Apple arm64 is officially supported, these will just be silenced here. -# TODO (sebbas): Check if official arm64 devices give linker warnings without this block. - +# Silence them here. if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")) if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") string(APPEND CMAKE_C_FLAGS " -fvisibility=hidden") -- cgit v1.2.3 From 350ad4bcb1b38ed07f5198a7340ebbe9ab856bf3 Mon Sep 17 00:00:00 2001 From: Siddhartha Jejurkar Date: Thu, 11 Mar 2021 16:51:01 +0100 Subject: Fix T86199: error when adding custom fluid diffusion preset Differential Revision: https://developer.blender.org/D10694 --- release/scripts/startup/bl_operators/presets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 5132b358f5e..cedbe542287 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -384,7 +384,7 @@ class AddPresetFluid(AddPresetBase, Operator): """Add or remove a Fluid Preset""" bl_idname = "fluid.preset_add" bl_label = "Add Fluid Preset" - preset_menu = "FLUID_MT_presets" + preset_menu = "FLUID_PT_presets" preset_defines = [ "fluid = bpy.context.fluid" -- cgit v1.2.3 From 9dfc81ccf10153385e8ff744ab2a9e2a25ce6606 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 02:58:02 +1100 Subject: Fix regression in 2cc5af9c553cfc00b7d4616445ad954597a92d94 The check for undo-depth increment/decrement assumed a newly loaded window manager would have a different pointer. This broke bl_animation_fcurves test indirectly, the change to undo-depth caused the redo panel to attempt to popup in background mode - which isn't supported. Now the pointer is unchanged, the undo-depth is assumed to match the value used when calling the operator. The undo-depth is now properly maintained between file loads, which is an improvement on the original behavior which reset it. --- source/blender/windowmanager/intern/wm_files.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index bd220e2ff95..8357dfd7417 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -311,6 +311,10 @@ static void wm_window_match_replace_by_file_wm(bContext *C, BLI_assert(bmain->relations == NULL); BKE_libblock_remap(bmain, wm, oldwm, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_USER_CLEAR); + /* Maintain the undo-depth between file loads. Useful so Python can perform + * nested operator calls that exit with the proper undo-depth. */ + wm->op_undo_depth = oldwm->op_undo_depth; + /* Simple pointer swapping step. */ BLI_remlink(current_wm_list, oldwm); BLI_remlink(readfile_wm_list, wm); -- cgit v1.2.3 From a1b01edf459e8c656174fab9e63e4d9b64a29388 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 11 Mar 2021 17:22:57 +0100 Subject: GPencil: Fix unreported Fill fails if the stroke was tagged In some situations the strokes could be tagged before filling, so it's necessary to reset before. --- source/blender/editors/gpencil/gpencil_fill.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 85130e89ad1..a3be475678d 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1710,6 +1710,17 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op) tgpf->mat = ma; + /* Untag strokes to be sure nothing is pending due any canceled process. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpf->gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_TAG) { + gps->flag &= ~GP_STROKE_TAG; + } + } + } + } + /* check whether the material was newly added */ if (totcol != tgpf->ob->totcol) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL); -- cgit v1.2.3 From ed2c4825d3e23441444e5d371278588c946e7551 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 15:42:22 +0100 Subject: Fix Asset Browser showing oudated list for changes done while browser is hidden Steps to reproduce were: * Open an Asset Browser * "Mark Asset" on some data-block * Change the Asset Browser into a different editor (not File Browser!) * "Clear Asset" on the data-block again, or mark another asset * Change back to the Asset Browser, it will show an outdated list Now the file-browser reloads local file data after spaces were changed. Note that the current notifier code doesn't limit the space-change notifiers to the affected spaces, so changing any visible space will trigger this. That's an issue to be fixed separately. --- source/blender/editors/space_file/space_file.c | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 039ab3d6907..993b1d9b69c 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -420,6 +420,15 @@ static void file_on_reload_callback_call(SpaceFile *sfile) sfile->runtime->on_reload_custom_data = NULL; } +static void file_reset_filelist_showing_main_data(ScrArea *area, SpaceFile *sfile) +{ + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view + * is cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } +} + static void file_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -446,6 +455,11 @@ static void file_listener(const wmSpaceTypeListenerParams *params) ED_area_tag_refresh(area); } break; + case ND_SPACE_CHANGED: + /* If the space was just turned into a file/asset browser, the file-list may need to be + * updated to reflect latest changes in main data. */ + file_reset_filelist_showing_main_data(area, sfile); + break; } switch (wmn->action) { case NA_JOB_FINISHED: @@ -462,11 +476,7 @@ static void file_listener(const wmSpaceTypeListenerParams *params) case NA_ADDED: case NA_REMOVED: case NA_EDITED: - if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if local asset data was changed. Refreshing this view - * is cheap and users expect this to be updated immediately. */ - file_tag_reset_list(area, sfile); - } + file_reset_filelist_showing_main_data(area, sfile); break; } break; @@ -890,13 +900,11 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID * { SpaceFile *sfile = (SpaceFile *)sl; - /* If the file shows main data (IDs), tag it for reset. */ - if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if main data was changed, don't even attempt remap pointers. - * We could give file list types a id-remap callback, but it's probably not worth it. - * Refreshing local file lists is relatively cheap. */ - file_tag_reset_list(area, sfile); - } + /* If the file shows main data (IDs), tag it for reset. + * Full reset of the file list if main data was changed, don't even attempt remap pointers. + * We could give file list types a id-remap callback, but it's probably not worth it. + * Refreshing local file lists is relatively cheap. */ + file_reset_filelist_showing_main_data(area, sfile); } /* only called once, from space/spacetypes.c */ -- cgit v1.2.3 From 46aa70cb486d719139ac43e5c9ac4b0fe998e202 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 17:30:39 +0100 Subject: UI: Avoid unnecessary redraws of unrelated editors on space changes When adding a notifier, `reference` data can be passed. The notifier system uses this to filter out listeners, for example if data of a scene changes, windows showing a different scene won't get the notifiers sent to their listeners. For the `NC_SPACE` notifiers, a number of places also passed the space as `reference`, but that wasn't used at all. The notifier would still be sent to all listeners in all windows (and the listeners didn't use it either). Causing some unnecessary updates (e.g. see ed2c4825d3e2344). With this commit, passing a space will make sure the notifier is only sent to that exact space. Some code seems to already have expected that to be the case. However there were some cases that passed the space as `reference` without reason, which would break with this commit (meaning they wouldn't redraw or update correctly). Corrected these so they don't pass the space anymore. --- source/blender/editors/gpencil/gpencil_edit.c | 3 +-- source/blender/editors/object/object_relations.c | 4 ++-- source/blender/editors/space_outliner/outliner_dragdrop.c | 2 +- source/blender/editors/space_view3d/view3d_buttons.c | 2 +- source/blender/editors/space_view3d/view3d_snap.c | 4 ++-- source/blender/editors/transform/transform_ops.c | 5 ++--- source/blender/windowmanager/WM_types.h | 3 +++ source/blender/windowmanager/intern/wm_event_system.c | 4 ++++ 8 files changed, 16 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index b03d2c6e795..4bbd475dd2c 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3095,7 +3095,6 @@ static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *op) const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); float *cursor = scene->cursor.location; float centroid[3] = {0.0f}; @@ -3125,7 +3124,7 @@ static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *op) } DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index e74d04ab17f..0aa739c2fc8 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1756,7 +1756,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) } DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C)); WM_event_add_notifier(C, NC_OBJECT, NULL); @@ -2712,7 +2712,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent DEG_id_tag_update(&base->object->id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 01fb0fc6f78..b55720c3d01 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -647,7 +647,7 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 36da0791c4f..17f60dfc210 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1575,7 +1575,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event } /* default for now */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt)) diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index cce9287679c..61eeafbe7c7 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -667,7 +667,7 @@ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) curs[1] = gridf * floorf(0.5f + curs[1] / gridf); curs[2] = gridf * floorf(0.5f + curs[2] / gridf); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); /* hrm */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* hrm */ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; @@ -913,7 +913,7 @@ static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op)) View3D *v3d = CTX_wm_view3d(C); if (snap_calc_active_center(C, false, scene->cursor.location)) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 01c00247a7a..9b5f15a2574 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -163,14 +163,13 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = { static int select_orientation_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); int orientation = RNA_enum_get(op->ptr, "orientation"); BKE_scene_orientation_slot_set_index(&scene->orientation_slots[SCE_ORIENT_DEFAULT], orientation); WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); struct wmMsgBus *mbus = CTX_wm_message_bus(C); WM_msg_publish_rna_prop(mbus, &scene->id, scene, TransformOrientationSlot, type); @@ -286,7 +285,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); } - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index b46a354c7ae..385a572ab85 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -287,6 +287,9 @@ typedef struct wmNotifier { #define NC_TEXT (12 << 24) #define NC_WORLD (13 << 24) #define NC_ANIMATION (14 << 24) +/* When passing a space as reference data with this (e.g. `WM_event_add_notifier(..., space)`), + * the notifier will only be sent to this space. That avoids unnecessary updates for unrelated + * spaces. */ #define NC_SPACE (15 << 24) #define NC_GEOM (16 << 24) #define NC_NODE (17 << 24) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index a39200537d5..33ba27c849c 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -577,6 +577,10 @@ void wm_event_do_notifiers(bContext *C) } ED_screen_areas_iter (win, screen, area) { + if ((note->category == NC_SPACE) && note->reference && + (note->reference != area->spacedata.first)) { + continue; + } wmSpaceTypeListenerParams area_params = { .window = win, .area = area, -- cgit v1.2.3 From 7092d6a7a31d9cde901828ea6abd76a66e5a7334 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 17:57:05 +0100 Subject: Fix warning from own previous commit --- source/blender/editors/space_view3d/view3d_snap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 61eeafbe7c7..72c62321e88 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -910,7 +910,6 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); if (snap_calc_active_center(C, false, scene->cursor.location)) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); -- cgit v1.2.3 From 670c1fdf64d1a64aef8eaa802f779d7c705afb77 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 11 Mar 2021 18:17:23 +0100 Subject: GPencil: Remove limitation to use only one Lattice modifier This limitation was necessary in older versions, but now can be removed. --- source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index b2a83e83c9e..ff493258b9b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -265,7 +265,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* structName */ "LatticeGpencilModifierData", /* structSize */ sizeof(LatticeGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, - /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, /* copyData */ copyData, -- cgit v1.2.3 From 1b1f8da5dde04f301c779e9426138b5cb76dc32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 11 Mar 2021 18:18:27 +0100 Subject: Cleanup: remove unnecessary `const` from function declaration No functional changes. --- source/blender/blenkernel/BKE_animsys.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 8666291cec8..d43332ae1ac 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -266,7 +266,7 @@ void BKE_animsys_evaluate_all_animation(struct Main *main, void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, const struct AnimationEvalContext *anim_eval_context, - const bool flush_to_original); + bool flush_to_original); /* Evaluate Action Group */ void animsys_evaluate_action_group(struct PointerRNA *ptr, -- cgit v1.2.3 From 8c6337e587bd2d738398474ce6068a748bd1b85b Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 11 Mar 2021 18:40:42 +0100 Subject: Fix missing UI updates, caused by own earlier commit Caused by 46aa70cb486d. RNA would send property update notifiers with the owner ID as `reference` data. Since above's commit we'd only send the notifiers to editors if the reference data address matches the space's address. So editors wouldn't get the notifiers at all. The owner ID for space properties is always the screen AFAIK. So allow notifiers with the screen as reference to be passed to editors as well, think this is reasonable to do either way. For example, steps to reproduce were: * Open Asset Browser * Mark some data-blocks of different types as assets (e.g. object & its material) * Switch between the categories in the Asset Browser. The asset list wouldn't be updated. --- source/blender/windowmanager/intern/wm_event_system.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 33ba27c849c..646aa71025c 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -577,9 +577,12 @@ void wm_event_do_notifiers(bContext *C) } ED_screen_areas_iter (win, screen, area) { - if ((note->category == NC_SPACE) && note->reference && - (note->reference != area->spacedata.first)) { - continue; + if ((note->category == NC_SPACE) && note->reference) { + /* Filter out notifiers sent to other spaces. RNA sets the reference to the owning ID + * though, the screen, so let notifiers through that reference the entire screen. */ + if ((note->reference != area->spacedata.first) && (note->reference != screen)) { + continue; + } } wmSpaceTypeListenerParams area_params = { .window = win, -- cgit v1.2.3 From afa30f1a9d2124f1e7d7e16cac8e1176a22029ed Mon Sep 17 00:00:00 2001 From: Fabian Schempp Date: Thu, 11 Mar 2021 18:53:29 +0100 Subject: Nodes: Fix drag link from output to already linked Multi-Input Socket This patch fixes a visual bug related to connecting an output socket to a Multi-Input Socket, that already has a link to that same output. In this case, the drag link got a new index and snapped to a new position. This path makes the drag link snap to the same position as the first link between the two sockets. Differential Revision: https://developer.blender.org/D10689 --- source/blender/editors/space_node/node_draw.cc | 8 ++++++-- source/blender/editors/space_node/node_relationships.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index bb0cd754c7b..f64ce771b25 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_map.hh" #include "BLI_math.h" +#include "BLI_set.hh" #include "BLI_span.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" @@ -81,6 +82,7 @@ # include "COM_compositor.h" #endif +using blender::Set; using blender::Span; using blender::Vector; @@ -1746,10 +1748,11 @@ static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) { if (socket->flag & SOCK_MULTI_INPUT) { + Set visited_from_sockets; socket->total_inputs = 0; LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if (link->tosock == socket) { - socket->total_inputs++; + visited_from_sockets.add(link->fromsock); } } /* Count temporary links going into this socket. */ @@ -1757,10 +1760,11 @@ static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode) LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { bNodeLink *link = (bNodeLink *)linkdata->data; if (link->tosock == socket) { - socket->total_inputs++; + visited_from_sockets.add(link->fromsock); } } } + socket->total_inputs = visited_from_sockets.size(); } } } diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 963349f876b..9293494a16a 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -890,10 +890,24 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) continue; } + /* Skip if tsock is already linked with this output. */ + bNodeLink *existing_link_connected_to_fromsock = NULL; + LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) { + if (existing_link->fromsock == link->fromsock && existing_link->tosock == tsock) { + existing_link_connected_to_fromsock = existing_link; + break; + } + } + /* attach links to the socket */ link->tonode = tnode; link->tosock = tsock; snode->runtime->last_node_hovered_while_dragging_a_link = tnode; + if (existing_link_connected_to_fromsock) { + link->multi_input_socket_index = + existing_link_connected_to_fromsock->multi_input_socket_index; + continue; + } sort_multi_input_socket_links(snode, tnode, link, cursor); } } -- cgit v1.2.3 From 60f7275f7f3cbf62561ac114a25844b396242b59 Mon Sep 17 00:00:00 2001 From: Fabian Schempp Date: Thu, 11 Mar 2021 23:06:16 +0100 Subject: Nodes: Add Attribute Remove Node This patch adds a node, that removes an attribute if possible, otherwise it adds an error message. Differential Revision: https://developer.blender.org/D10697 --- release/scripts/startup/nodeitems_builtins.py | 1 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/blenkernel/intern/node.cc | 1 + source/blender/nodes/CMakeLists.txt | 1 + source/blender/nodes/NOD_geometry.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + 6 files changed, 6 insertions(+) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 83e72e6f84c..f9a789f800b 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -493,6 +493,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeAttributeSampleTexture"), NodeItem("GeometryNodeAttributeCombineXYZ"), NodeItem("GeometryNodeAttributeSeparateXYZ"), + NodeItem("GeometryNodeAttributeRemove"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ NodeItem("ShaderNodeValToRGB"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f5f65e71f7f..2c543a0a014 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1372,6 +1372,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027 #define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028 #define GEO_NODE_SUBDIVIDE 1029 +#define GEO_NODE_ATTRIBUTE_REMOVE 1030 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 9615fbc31e7..528088b2ee7 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4795,6 +4795,7 @@ static void registerGeometryNodes() register_node_type_geo_attribute_randomize(); register_node_type_geo_attribute_separate_xyz(); register_node_type_geo_attribute_vector_math(); + register_node_type_geo_attribute_remove(); register_node_type_geo_boolean(); register_node_type_geo_collection_info(); register_node_type_geo_edge_split(); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d89cf2ecefa..9408e5348dd 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -154,6 +154,7 @@ set(SRC geometry/nodes/node_geo_attribute_sample_texture.cc geometry/nodes/node_geo_attribute_separate_xyz.cc geometry/nodes/node_geo_attribute_vector_math.cc + geometry/nodes/node_geo_attribute_remove.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_collection_info.cc geometry/nodes/node_geo_common.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index b094256190c..d7f56464b36 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -37,6 +37,7 @@ void register_node_type_geo_attribute_proximity(void); void register_node_type_geo_attribute_randomize(void); void register_node_type_geo_attribute_separate_xyz(void); void register_node_type_geo_attribute_vector_math(void); +void register_node_type_geo_attribute_remove(void); void register_node_type_geo_boolean(void); void register_node_type_geo_collection_info(void); void register_node_type_geo_edge_split(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 22204d7204e..6669f47c6aa 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -299,6 +299,7 @@ DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_T DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "") DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "") /* undefine macros */ #undef DefNode -- cgit v1.2.3 From 3256f0d52c8f172c340a7ef5154e780308e777ca Mon Sep 17 00:00:00 2001 From: Fabian Schempp Date: Thu, 11 Mar 2021 23:42:19 +0100 Subject: Added missing file to last commit: Nodes: Add Attribute Remove Node D10697 --- .../geometry/nodes/node_geo_attribute_remove.cc | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc new file mode 100644 index 00000000000..bf9bda67045 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_attribute_remove_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_remove_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void remove_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string attribute_name = params.get_input("Attribute"); + if (attribute_name.empty()) { + return; + } + + if (!component.attribute_try_delete(attribute_name)) { + params.error_message_add(NodeWarningType::Error, + TIP_("Cannot delete attribute with name \"") + attribute_name + "\""); + } +} + +static void geo_node_attribute_remove_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + geometry_set = geometry_set_realize_instances(geometry_set); + + if (geometry_set.has()) { + remove_attribute(geometry_set.get_component_for_write(), params); + } + if (geometry_set.has()) { + remove_attribute(geometry_set.get_component_for_write(), params); + } + + params.set_output("Geometry", geometry_set); +} +} // namespace blender::nodes + +void register_node_type_geo_attribute_remove() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_attribute_remove_in, geo_node_attribute_remove_out); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec; + nodeRegisterType(&ntype); +} -- cgit v1.2.3 From 2ebf4fbbfb9afc2439ddce139243d226087662e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 11 Mar 2021 23:45:42 +0100 Subject: Alembic procedural: fix potential zero scale matrix generation This can happen during user edits or with files missing the global scale property. --- intern/cycles/render/alembic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 468ebf7140f..4a9d1dbb04b 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1017,6 +1017,10 @@ void AlembicObject::setup_transform_cache(float scale) cached_data.transforms.clear(); cached_data.transforms.invalidate_last_loaded_time(); + if (scale == 0.0f) { + scale = 1.0f; + } + if (xform_time_sampling) { cached_data.transforms.set_time_sampling(*xform_time_sampling); } -- cgit v1.2.3 From 62e2fdf40b6fa19e10f9aea5ee1a7344b2e9e88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 11 Mar 2021 23:47:23 +0100 Subject: Cleanup: unused variable --- intern/cycles/render/alembic.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 4a9d1dbb04b..abe4dea0b3e 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -402,8 +402,6 @@ static void add_uvs(AlembicProcedural *proc, } const ISampleSelector iss = ISampleSelector(time); - const IV2fGeomParam::Sample sample = uvs.getExpandedValue(iss); - const IV2fGeomParam::Sample uvsample = uvs.getIndexedValue(iss); if (!uvsample.valid()) { -- cgit v1.2.3 From 7a028d5b997e6f0fd2da3d6446943d2b9059f9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 11 Mar 2021 23:51:54 +0100 Subject: Alembic procedural: fix missing attribute update We need to explicitely tag the Attribute and AttributeSet as modified if we change or add/remove data. This is more of a bandaid until attributes handling is refactored to be able to reuse routines from the Attribute API. --- intern/cycles/render/alembic.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index abe4dea0b3e..1af38aa247e 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1284,6 +1284,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data, } memcpy(attr->data(), attr_data->data(), attr_data->size()); + attr->modified = true; } /* remove any attributes not in cached_attributes */ @@ -1291,6 +1292,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data, for (it = attributes.attributes.begin(); it != attributes.attributes.end();) { if (cached_attributes.find(&(*it)) == cached_attributes.end()) { attributes.attributes.erase(it++); + attributes.modified = true; continue; } -- cgit v1.2.3 From 7017844c5eca72046654b27ceee2f9528edbe488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 12 Mar 2021 00:15:07 +0100 Subject: Alembic procedural: move cache building out of object update methods This will help support instancing as cache building is now decoupled from the logic to update the Nodes' sockets as data (and cache) will need to be shared by different Geometries somehow, and also simplify implementing different data caching methods by centralizing this operation. --- intern/cycles/render/alembic.cpp | 173 ++++++++++++++++++--------------------- intern/cycles/render/alembic.h | 17 ++-- 2 files changed, 83 insertions(+), 107 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 1af38aa247e..de51e6fe0ac 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -715,7 +715,6 @@ void AlembicObject::read_face_sets(SchemaType &schema, void AlembicObject::load_all_data(AlembicProcedural *proc, IPolyMeshSchema &schema, - float scale, Progress &progress) { cached_data.clear(); @@ -778,19 +777,10 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, add_uvs(proc, uvs, cached_data, progress); } - if (progress.get_cancel()) { - return; - } - - setup_transform_cache(scale); - data_loaded = true; } -void AlembicObject::load_all_data(AlembicProcedural *proc, - ISubDSchema &schema, - float scale, - Progress &progress) +void AlembicObject::load_all_data(AlembicProcedural *proc, ISubDSchema &schema, Progress &progress) { cached_data.clear(); @@ -918,14 +908,11 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, return; } - setup_transform_cache(scale); - data_loaded = true; } void AlembicObject::load_all_data(AlembicProcedural *proc, const ICurvesSchema &schema, - float scale, Progress &progress, float default_radius) { @@ -1005,8 +992,6 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, // TODO(@kevindietrich): attributes, need example files - setup_transform_cache(scale); - data_loaded = true; } @@ -1410,6 +1395,8 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate); + build_caches(progress); + foreach (Node *node, objects) { AlembicObject *object = static_cast(node); @@ -1418,19 +1405,19 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) } /* skip constant objects */ - if (object->has_data_loaded() && object->is_constant() && !object->is_modified() && - !object->need_shader_update && !scale_is_modified()) { + if (object->is_constant() && !object->is_modified() && !object->need_shader_update && + !scale_is_modified()) { continue; } if (object->schema_type == AlembicObject::POLY_MESH) { - read_mesh(object, frame_time, progress); + read_mesh(object, frame_time); } else if (object->schema_type == AlembicObject::CURVES) { - read_curves(object, frame_time, progress); + read_curves(object, frame_time); } else if (object->schema_type == AlembicObject::SUBD) { - read_subd(object, frame_time, progress); + read_subd(object, frame_time); } object->clear_modified(); @@ -1519,29 +1506,9 @@ void AlembicProcedural::load_objects(Progress &progress) } } -void AlembicProcedural::read_mesh(AlembicObject *abc_object, - Abc::chrono_t frame_time, - Progress &progress) +void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time) { - IPolyMesh polymesh(abc_object->iobject, Alembic::Abc::kWrapExisting); - - Mesh *mesh = static_cast(abc_object->get_object()->get_geometry()); - CachedData &cached_data = abc_object->get_cached_data(); - IPolyMeshSchema schema = polymesh.getSchema(); - - if (!abc_object->has_data_loaded()) { - abc_object->load_all_data(this, schema, scale, progress); - } - else { - if (abc_object->need_shader_update) { - abc_object->update_shader_attributes(schema.getArbGeomParams(), progress); - } - - if (scale_is_modified()) { - abc_object->setup_transform_cache(scale); - } - } /* update sockets */ @@ -1552,6 +1519,8 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, object->tag_update(scene_); } + Mesh *mesh = static_cast(object->get_geometry()); + cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket()); cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket()); @@ -1594,34 +1563,8 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, } } -void AlembicProcedural::read_subd(AlembicObject *abc_object, - Abc::chrono_t frame_time, - Progress &progress) +void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time) { - ISubD subd_mesh(abc_object->iobject, Alembic::Abc::kWrapExisting); - ISubDSchema schema = subd_mesh.getSchema(); - - Mesh *mesh = static_cast(abc_object->get_object()->get_geometry()); - - /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */ - mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK); - - if (!abc_object->has_data_loaded()) { - abc_object->load_all_data(this, schema, scale, progress); - } - else { - if (abc_object->need_shader_update) { - abc_object->update_shader_attributes(schema.getArbGeomParams(), progress); - } - - if (scale_is_modified()) { - abc_object->setup_transform_cache(scale); - } - } - - mesh->set_subd_max_level(abc_object->get_subd_max_level()); - mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate()); - CachedData &cached_data = abc_object->get_cached_data(); if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) { @@ -1629,6 +1572,17 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, cached_data.invalidate_last_loaded_time(); } + /* Update sockets. */ + + Object *object = abc_object->get_object(); + cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); + + if (object->is_modified()) { + object->tag_update(scene_); + } + + Mesh *mesh = static_cast(object->get_geometry()); + /* Cycles overwrites the original triangles when computing displacement, so we always have to * repass the data if something is animated (vertices most likely) to avoid buffer overflows. */ if (!cached_data.is_constant()) { @@ -1641,14 +1595,10 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, mesh->clear_non_sockets(); - /* Update sockets. */ - - Object *object = abc_object->get_object(); - cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); - - if (object->is_modified()) { - object->tag_update(scene_); - } + /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */ + mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK); + mesh->set_subd_max_level(abc_object->get_subd_max_level()); + mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate()); cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket()); @@ -1703,25 +1653,8 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, } } -void AlembicProcedural::read_curves(AlembicObject *abc_object, - Abc::chrono_t frame_time, - Progress &progress) +void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time) { - ICurves curves(abc_object->iobject, Alembic::Abc::kWrapExisting); - Hair *hair = static_cast(abc_object->get_object()->get_geometry()); - - ICurvesSchema schema = curves.getSchema(); - - if (!abc_object->has_data_loaded() || default_radius_is_modified() || - abc_object->radius_scale_is_modified()) { - abc_object->load_all_data(this, schema, scale, progress, default_radius); - } - else { - if (scale_is_modified()) { - abc_object->setup_transform_cache(scale); - } - } - CachedData &cached_data = abc_object->get_cached_data(); /* update sockets */ @@ -1733,6 +1666,8 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, object->tag_update(scene_); } + Hair *hair = static_cast(object->get_geometry()); + cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket()); cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket()); @@ -1884,6 +1819,54 @@ void AlembicProcedural::walk_hierarchy( } } +void AlembicProcedural::build_caches(Progress &progress) +{ + for (Node *node : objects) { + AlembicObject *object = static_cast(node); + + if (progress.get_cancel()) { + return; + } + + if (object->schema_type == AlembicObject::POLY_MESH) { + if (!object->has_data_loaded()) { + IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting); + IPolyMeshSchema schema = polymesh.getSchema(); + object->load_all_data(this, schema, progress); + } + else if (object->need_shader_update) { + IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting); + IPolyMeshSchema schema = polymesh.getSchema(); + object->update_shader_attributes(schema.getArbGeomParams(), progress); + } + } + else if (object->schema_type == AlembicObject::CURVES) { + if (!object->has_data_loaded() || default_radius_is_modified() || + object->radius_scale_is_modified()) { + ICurves curves(object->iobject, Alembic::Abc::kWrapExisting); + ICurvesSchema schema = curves.getSchema(); + object->load_all_data(this, schema, progress, default_radius); + } + } + else if (object->schema_type == AlembicObject::SUBD) { + if (!object->has_data_loaded()) { + ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting); + ISubDSchema schema = subd_mesh.getSchema(); + object->load_all_data(this, schema, progress); + } + else if (object->need_shader_update) { + ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting); + ISubDSchema schema = subd_mesh.getSchema(); + object->update_shader_attributes(schema.getArbGeomParams(), progress); + } + } + + if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) { + object->setup_transform_cache(scale); + } + } +} + CCL_NAMESPACE_END #endif diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 587843201ce..a84e97f551b 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -254,15 +254,12 @@ class AlembicObject : public Node { void load_all_data(AlembicProcedural *proc, Alembic::AbcGeom::IPolyMeshSchema &schema, - float scale, Progress &progress); void load_all_data(AlembicProcedural *proc, Alembic::AbcGeom::ISubDSchema &schema, - float scale, Progress &progress); void load_all_data(AlembicProcedural *proc, const Alembic::AbcGeom::ICurvesSchema &schema, - float scale, Progress &progress, float default_radius); @@ -396,21 +393,17 @@ class AlembicProcedural : public Procedural { /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_mesh(AlembicObject *abc_object, - Alembic::AbcGeom::Abc::chrono_t frame_time, - Progress &progress); + void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_curves(AlembicObject *abc_object, - Alembic::AbcGeom::Abc::chrono_t frame_time, - Progress &progress); + void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_subd(AlembicObject *abc_object, - Alembic::AbcGeom::Abc::chrono_t frame_time, - Progress &progress); + void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); + + void build_caches(Progress &progress); }; CCL_NAMESPACE_END -- cgit v1.2.3 From d72fc36ec5c632cafa2f9e2c8897ce81fc83a372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 12 Mar 2021 01:30:12 +0100 Subject: Alembic procedural: add support for instancing Inside of the procedural, instances are AlembicObjects which point to the AlembicObject that they instance. In Alembic, an instance is an untyped Object pointing to the original (instanced) one through its source path. During the archive traversal we detect such instances and, only if the instanced object is asked to be rendered, set the instance's AlembicObject to point to the original's AlembicObject. Cycles Object Nodes are created for each AlembicObject, but only for non-instances are Geometries created, which are then shared between Object Nodes. It is supposed, and expected, that all instances share the same shaders, which will be set to be the ones found on the original object. As for caching, the data cache for an AlembicObject is only valid for non-instances and should not be read to or from as it is implicitly shared. --- intern/cycles/render/alembic.cpp | 102 +++++++++++++++++++++++++++++++++------ intern/cycles/render/alembic.h | 2 + 2 files changed, 89 insertions(+), 15 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index de51e6fe0ac..59454eac8a5 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -719,6 +719,11 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, { cached_data.clear(); + /* Only load data for the original Geometry. */ + if (instance_of) { + return; + } + const TimeSamplingPtr time_sampling = schema.getTimeSampling(); cached_data.set_time_sampling(*time_sampling); @@ -784,6 +789,11 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, ISubDSchema &schema, { cached_data.clear(); + /* Only load data for the original Geometry. */ + if (instance_of) { + return; + } + AttributeRequestSet requested_attributes = get_requested_attributes(); const TimeSamplingPtr time_sampling = schema.getTimeSampling(); @@ -918,6 +928,11 @@ void AlembicObject::load_all_data(AlembicProcedural *proc, { cached_data.clear(); + /* Only load data for the original Geometry. */ + if (instance_of) { + return; + } + const TimeSamplingPtr time_sampling = schema.getTimeSampling(); cached_data.set_time_sampling(*time_sampling); @@ -1480,22 +1495,24 @@ void AlembicProcedural::load_objects(Progress &progress) Geometry *geometry = nullptr; - if (abc_object->schema_type == AlembicObject::CURVES) { - geometry = scene_->create_node(); - } - else if (abc_object->schema_type == AlembicObject::POLY_MESH || - abc_object->schema_type == AlembicObject::SUBD) { - geometry = scene_->create_node(); - } - else { - continue; - } + if (!abc_object->instance_of) { + if (abc_object->schema_type == AlembicObject::CURVES) { + geometry = scene_->create_node(); + } + else if (abc_object->schema_type == AlembicObject::POLY_MESH || + abc_object->schema_type == AlembicObject::SUBD) { + geometry = scene_->create_node(); + } + else { + continue; + } - geometry->set_owner(this); - geometry->name = abc_object->iobject.getName(); + geometry->set_owner(this); + geometry->name = abc_object->iobject.getName(); - array used_shaders = abc_object->get_used_shaders(); - geometry->set_used_shaders(used_shaders); + array used_shaders = abc_object->get_used_shaders(); + geometry->set_used_shaders(used_shaders); + } Object *object = scene_->create_node(); object->set_owner(this); @@ -1504,6 +1521,17 @@ void AlembicProcedural::load_objects(Progress &progress) abc_object->set_object(object); } + + /* Share geometries between instances. */ + foreach (Node *node, objects) { + AlembicObject *abc_object = static_cast(node); + + if (abc_object->instance_of) { + abc_object->get_object()->set_geometry( + abc_object->instance_of->get_object()->get_geometry()); + abc_object->schema_type = abc_object->instance_of->schema_type; + } + } } void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time) @@ -1519,6 +1547,11 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame object->tag_update(scene_); } + /* Only update sockets for the original Geometry. */ + if (abc_object->instance_of) { + return; + } + Mesh *mesh = static_cast(object->get_geometry()); cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket()); @@ -1581,6 +1614,11 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame object->tag_update(scene_); } + /* Only update sockets for the original Geometry. */ + if (abc_object->instance_of) { + return; + } + Mesh *mesh = static_cast(object->get_geometry()); /* Cycles overwrites the original triangles when computing displacement, so we always have to @@ -1666,6 +1704,11 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra object->tag_update(scene_); } + /* Only update sockets for the original Geometry. */ + if (abc_object->instance_of) { + return; + } + Hair *hair = static_cast(object->get_geometry()); cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket()); @@ -1806,9 +1849,38 @@ void AlembicProcedural::walk_hierarchy( else if (IFaceSet::matches(header)) { // ignore the face set, it will be read along with the data } + else if (IPoints::matches(header)) { + // unsupported for now + } + else if (INuPatch::matches(header)) { + // unsupported for now + } else { - // unsupported type for now (Points, NuPatch) next_object = parent.getChild(header.getName()); + + if (next_object.isInstanceRoot()) { + unordered_map::const_iterator iter; + + /* Was this object asked to be rendered? */ + iter = object_map.find(next_object.getFullName()); + + if (iter != object_map.end()) { + AlembicObject *abc_object = iter->second; + + /* Only try to render an instance if the original object is also rendered. */ + iter = object_map.find(next_object.instanceSourcePath()); + + if (iter != object_map.end()) { + abc_object->iobject = next_object; + abc_object->instance_of = iter->second; + + if (matrix_samples_data.samples) { + abc_object->xform_samples = *matrix_samples_data.samples; + abc_object->xform_time_sampling = matrix_samples_data.time_sampling; + } + } + } + } } if (next_object.valid()) { diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index a84e97f551b..6552336e6ab 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -276,6 +276,8 @@ class AlembicObject : public Node { bool need_shader_update = true; + AlembicObject *instance_of = nullptr; + Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling; MatrixSampleMap xform_samples; Alembic::AbcGeom::IObject iobject; -- cgit v1.2.3 From 8922d177c1019cc846928a3d5344991e000eeaa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 12 Mar 2021 01:57:41 +0100 Subject: Alembic procedural: specific result type for cache lookups This type, CacheLookupResult, holds the data for the current time, or an explanation as to why no data is available (already loaded, or simply nothing available). This is useful to document the behavior of the code but also, in future changes, to respond appropriately for missing data. --- intern/cycles/render/alembic.cpp | 29 ++++++++----- intern/cycles/render/alembic.h | 92 +++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 21 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 59454eac8a5..0841a3c09cd 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -408,8 +408,10 @@ static void add_uvs(AlembicProcedural *proc, continue; } - const array *triangles = cached_data.triangles.data_for_time_no_check(time); - const array *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); + const array *triangles_loops = + cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null(); if (!triangles || !triangles_loops) { continue; @@ -456,7 +458,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices, *normals.getTimeSampling()); attr.std = ATTR_STD_VERTEX_NORMAL; - const array *vertices = cached_data.vertices.data_for_time_no_check(time); + const array *vertices = + cached_data.vertices.data_for_time_no_check(time).get_data_or_null(); if (!vertices) { return; @@ -491,7 +494,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices, *normals.getTimeSampling()); attr.std = ATTR_STD_VERTEX_NORMAL; - const array *vertices = cached_data.vertices.data_for_time_no_check(time); + const array *vertices = + cached_data.vertices.data_for_time_no_check(time).get_data_or_null(); if (!vertices) { return; @@ -1109,9 +1113,10 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER; attribute.type_desc = TypeFloat2; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); - const array *triangles_loops = cached_data.triangles_loops.data_for_time_no_check( - time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); + const array *triangles_loops = + cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null(); if (!triangles || !triangles_loops) { return; @@ -1164,7 +1169,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER_BYTE; attribute.type_desc = TypeRGBA; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); if (!triangles) { return; @@ -1220,7 +1226,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER_BYTE; attribute.type_desc = TypeRGBA; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); if (!triangles) { return; @@ -1259,7 +1266,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data, set cached_attributes; for (CachedData::CachedAttribute &attribute : cached_data.attributes) { - const array *attr_data = attribute.data.data_for_time(frame_time); + const array *attr_data = attribute.data.data_for_time(frame_time).get_data_or_null(); Attribute *attr = nullptr; if (attribute.std != ATTR_STD_NONE) { @@ -1558,7 +1565,7 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket()); - array *triangle_data = cached_data.triangles.data_for_time(frame_time); + array *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null(); if (triangle_data) { array triangles; array smooth; diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 6552336e6ab..0fc02f1da23 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -50,6 +50,78 @@ template struct is_array : public std::false_type { template struct is_array> : public std::true_type { }; +/* Holds the data for a cache lookup at a given time, as well as informations to + * help disambiguate successes or failures to get data from the cache. */ +template class CacheLookupResult { + enum class State { + NEW_DATA, + ALREADY_LOADED, + NO_DATA_FOR_TIME, + }; + + T *data; + State state; + + protected: + /* Prevent default construction outside of the class: for a valid result, we + * should use the static functions below. */ + CacheLookupResult() = default; + + public: + static CacheLookupResult new_data(T *data_) + { + CacheLookupResult result; + result.data = data_; + result.state = State::NEW_DATA; + return result; + } + + static CacheLookupResult no_data_found_for_time() + { + CacheLookupResult result; + result.data = nullptr; + result.state = State::NO_DATA_FOR_TIME; + return result; + } + + static CacheLookupResult already_loaded() + { + CacheLookupResult result; + result.data = nullptr; + result.state = State::ALREADY_LOADED; + return result; + } + + /* This should only be call if new data is available. */ + const T &get_data() const + { + assert(state == State::NEW_DATA); + assert(data != nullptr); + return *data; + } + + T *get_data_or_null() const + { + // data_ should already be null if there is no new data so no need to check + return data; + } + + bool has_new_data() const + { + return state == State::NEW_DATA; + } + + bool has_already_loaded() const + { + return state == State::ALREADY_LOADED; + } + + bool has_no_data_for_time() const + { + return state == State::NO_DATA_FOR_TIME; + } +}; + /* Store the data set for an animation at every time points, or at the beginning of the animation * for constant data. * @@ -79,10 +151,10 @@ template class DataStore { /* Get the data for the specified time. * Return nullptr if there is no data or if the data for this time was already loaded. */ - T *data_for_time(double time) + CacheLookupResult data_for_time(double time) { if (size() == 0) { - return nullptr; + return CacheLookupResult::no_data_found_for_time(); } std::pair index_pair; @@ -90,26 +162,26 @@ template class DataStore { DataTimePair &data_pair = data[index_pair.first]; if (last_loaded_time == data_pair.time) { - return nullptr; + return CacheLookupResult::already_loaded(); } last_loaded_time = data_pair.time; - return &data_pair.data; + return CacheLookupResult::new_data(&data_pair.data); } /* get the data for the specified time, but do not check if the data was already loaded for this * time return nullptr if there is no data */ - T *data_for_time_no_check(double time) + CacheLookupResult data_for_time_no_check(double time) { if (size() == 0) { - return nullptr; + return CacheLookupResult::no_data_found_for_time(); } std::pair index_pair; index_pair = time_sampling.getNearIndex(time, data.size()); DataTimePair &data_pair = data[index_pair.first]; - return &data_pair.data; + return CacheLookupResult::new_data(&data_pair.data); } void add_data(T &data_, double time) @@ -149,15 +221,15 @@ template class DataStore { * data for this time or it was already loaded, do nothing. */ void copy_to_socket(double time, Node *node, const SocketType *socket) { - T *data_ = data_for_time(time); + CacheLookupResult result = data_for_time(time); - if (data_ == nullptr) { + if (!result.has_new_data()) { return; } /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the * arrays to avoid reloading the data */ - T value = *data_; + T value = result.get_data(); node->set(*socket, value); } }; -- cgit v1.2.3 From 406d9749d8dfa18c2e2ab04ba9b17cfd310f225d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 12:49:59 +1100 Subject: Cleanup: redundant outliner includes --- source/blender/editors/space_outliner/outliner_collections.c | 2 -- source/blender/editors/space_outliner/outliner_dragdrop.c | 10 ---------- source/blender/editors/space_outliner/outliner_draw.c | 5 ----- source/blender/editors/space_outliner/outliner_edit.c | 10 ---------- source/blender/editors/space_outliner/outliner_select.c | 9 --------- source/blender/editors/space_outliner/outliner_tree.c | 9 --------- 6 files changed, 45 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index d54e35f659c..062d2e2b5d1 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -49,8 +49,6 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -#include "UI_resources.h" - #include "outliner_intern.h" /* own include */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index b55720c3d01..b3b36811411 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -26,28 +26,21 @@ #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" -#include "DNA_constraint_types.h" #include "DNA_material_types.h" -#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" #include "BLI_listbase.h" -#include "BLI_string.h" #include "BLT_translation.h" #include "BKE_collection.h" -#include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_layer.h" -#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_report.h" -#include "BKE_scene.h" -#include "BKE_shader_fx.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -57,12 +50,9 @@ #include "ED_screen.h" #include "UI_interface.h" -#include "UI_resources.h" #include "UI_view2d.h" #include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 690adb09570..5b4a45f6115 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -21,7 +21,6 @@ * \ingroup spoutliner */ -#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" @@ -45,7 +44,6 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_fcurve.h" #include "BKE_gpencil.h" #include "BKE_idtype.h" #include "BKE_layer.h" @@ -56,14 +54,11 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_report.h" -#include "BKE_scene.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "ED_armature.h" -#include "ED_keyframing.h" -#include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 18abe17d515..5501e52d69b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -28,7 +28,6 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_collection_types.h" -#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -43,27 +42,19 @@ #include "BKE_appdir.h" #include "BKE_armature.h" #include "BKE_blender_copybuffer.h" -#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_idtype.h" -#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_outliner_treehash.h" #include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "../blenloader/BLO_readfile.h" - #include "ED_keyframing.h" -#include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" #include "ED_select_utils.h" @@ -72,7 +63,6 @@ #include "WM_types.h" #include "UI_interface.h" -#include "UI_resources.h" #include "UI_view2d.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index d53a37fa60e..50f089f894a 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -27,17 +27,13 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" -#include "DNA_constraint_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_light_types.h" -#include "DNA_material_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_shader_fx_types.h" -#include "DNA_world_types.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" @@ -52,19 +48,15 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" -#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_shader_fx.h" -#include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "ED_armature.h" #include "ED_buttons.h" -#include "ED_gpencil.h" #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -76,7 +68,6 @@ #include "SEQ_sequencer.h" #include "WM_api.h" -#include "WM_toolsystem.h" #include "WM_types.h" #include "UI_interface.h" diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 36a9549c9b2..573fb492613 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -62,23 +62,14 @@ #include "BLT_translation.h" #include "BKE_armature.h" -#include "BKE_fcurve_driver.h" -#include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" -#include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_outliner_treehash.h" -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" - #include "ED_screen.h" -#include "WM_api.h" -#include "WM_types.h" - #include "RNA_access.h" #include "UI_interface.h" -- cgit v1.2.3 From d3fa576aa704a1eeed75244d4b2a124989cd0d50 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 12:50:36 +1100 Subject: Cleanup: redundant flag check --- source/blender/editors/gpencil/gpencil_fill.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index a3be475678d..4749f40fac5 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1714,9 +1714,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op) LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpf->gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - if (gps->flag & GP_STROKE_TAG) { - gps->flag &= ~GP_STROKE_TAG; - } + gps->flag &= ~GP_STROKE_TAG; } } } -- cgit v1.2.3 From 8125731caef79690dd25a839b1fc8ad48efac7d1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 12:51:38 +1100 Subject: Cleanup: break out of loop early --- source/blender/modifiers/intern/MOD_uvproject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 487250eb4e3..3162a33edc2 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -337,6 +337,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object"); if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) { has_camera = true; + break; } } RNA_END; -- cgit v1.2.3 From 7f4530dad2ef5f9370f5c36261387be0127f02f6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 12:52:23 +1100 Subject: Cleanup: incorrect doxy section title Also correct typo. --- source/blender/editors/sculpt_paint/sculpt_intern.h | 2 +- source/blender/editors/space_file/file_ops.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 16c2996e392..c323a4d744a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1254,7 +1254,7 @@ typedef struct FilterCache { float *sharpen_factor; float (*detail_directions)[3]; - /* Filter orientaiton. */ + /* Filter orientation. */ SculptFilterOrientation orientation; float obmat[4][4]; float obmat_inv[4][4]; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index b82290205c7..bd6b15bdf74 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -962,7 +962,7 @@ void FILE_OT_select_all(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Select All Operator +/** \name View Selected Operator * \{ */ static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) -- cgit v1.2.3 From 2e9fb211c6c8d69b2dc68c05b90a07c6eb9cc37d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 13:39:08 +1100 Subject: Cleanup: make_source_archive.py minor changes & comments - Add notes on portability. - Use encoding argument for all file IO. - Use integer math to calculate major/minor version, while float division should be fine prefer matching Blender. --- build_files/utils/make_source_archive.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/build_files/utils/make_source_archive.py b/build_files/utils/make_source_archive.py index 24928742a2d..271ca358f7e 100755 --- a/build_files/utils/make_source_archive.py +++ b/build_files/utils/make_source_archive.py @@ -9,6 +9,10 @@ from typing import Iterable, TextIO # This script can run from any location, # output is created in the $CWD +# +# NOTE: while the Python part of this script is portable, +# it relies on external commands typically found on GNU/Linux. +# Support for other platforms could be added by moving GNU `tar` & `md5sum` use to Python. SKIP_NAMES = { ".gitignore", @@ -52,8 +56,9 @@ class BlenderVersion: >>> str(BlenderVersion(327, 0, "release")) '3.27.0' """ - - as_string = f"{self.version/100:.2f}.{self.patch}" + version_major = self.version // 100 + version_minor = self.version % 100 + as_string = f"{version_major}.{version_minor}.{self.patch}" if self.is_release: return as_string return f"{as_string}-{self.cycle}" @@ -101,6 +106,7 @@ def submodules_to_manifest(version: BlenderVersion, outfile: TextIO) -> None: for line in git_command("submodule"): submodule = line.split()[1] + # Don't use native slashes as GIT for MS-Windows outputs forward slashes. if skip_addon_contrib and submodule == "release/scripts/addons_contrib": continue @@ -110,6 +116,7 @@ def submodules_to_manifest(version: BlenderVersion, outfile: TextIO) -> None: def create_tarball(version: BlenderVersion, tarball: Path, manifest: Path) -> None: print(f'Creating archive: "{tarball}" ...', end="", flush=True) + # Requires GNU `tar`, since `--transform` is used. command = [ "tar", "--transform", @@ -139,7 +146,7 @@ def create_checksum_file(tarball: Path) -> None: md5_cmd = subprocess.run( command, stdout=subprocess.PIPE, check=True, text=True, timeout=300 ) - with md5_path.open("w") as outfile: + with md5_path.open("w", encoding="utf-8") as outfile: outfile.write(md5_cmd.stdout) print("OK") -- cgit v1.2.3 From 2a5f22c1afc9d143f3e1c784a0139e0d990d5a4a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 15:35:13 +1100 Subject: Cleanup: set the window manager to the updated context on load While this happened to be corrected by code that runs afterwards, leaving this in an invalid state could cause problems in the future. --- source/blender/windowmanager/intern/wm_files.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 8357dfd7417..227520ed3f9 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -322,6 +322,9 @@ static void wm_window_match_replace_by_file_wm(bContext *C, SWAP(wmWindowManager *, oldwm, wm); BLI_addhead(current_wm_list, oldwm); BLI_addhead(readfile_wm_list, wm); + + /* Don't leave the old pointer in the context. */ + CTX_wm_manager_set(C, wm); } bool has_match = false; -- cgit v1.2.3 From a5c44265a3368020bc9524696dae94caa9419e2c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Mar 2021 15:58:12 +1100 Subject: Cleanup: remove workaround for MSVC PyTypeObject declarations This is no longer needed for MSVC-2017. --- source/blender/python/intern/bpy_library_load.c | 8 ++------ source/blender/python/intern/bpy_rna.c | 21 +++++---------------- source/blender/python/intern/bpy_rna_data.c | 4 ++-- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 1ee14df24cf..96ff6a111d9 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -118,8 +118,8 @@ static PyTypeObject bpy_lib_Type = { NULL, /* reprfunc tp_str; */ /* will only use these if this is a subtype of a py class */ - NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ + PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ /* Functions to access object as input/output buffer */ NULL, /* PyBufferProcs *tp_as_buffer; */ @@ -498,10 +498,6 @@ PyMethodDef BPY_library_load_method_def = { int BPY_library_load_type_ready(void) { - - /* some compilers don't like accessing this directly, delay assignment */ - bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr; - if (PyType_Ready(&bpy_lib_Type) < 0) { return -1; } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 7a43c9cb997..fab73d0f3dc 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7078,13 +7078,9 @@ static PyTypeObject pyrna_prop_collection_iter_Type = { NULL, /* ternaryfunc tp_call; */ NULL, /* reprfunc tp_str; */ -/* will only use these if this is a subtype of a py class */ -# if defined(_MSC_VER) - NULL, /* defer assignment */ -# else + /* will only use these if this is a subtype of a py class */ PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */ -# endif - NULL, /* setattrofunc tp_setattro; */ + NULL, /* setattrofunc tp_setattro; */ /* Functions to access object as input/output buffer */ NULL, /* PyBufferProcs *tp_as_buffer; */ @@ -7110,13 +7106,9 @@ static PyTypeObject pyrna_prop_collection_iter_Type = { # else 0, # endif -/*** Added in release 2.2 ***/ -/* Iterators */ -# if defined(_MSC_VER) - NULL, /* defer assignment */ -# else - PyObject_SelfIter, /* getiterfunc tp_iter; */ -# endif + /*** Added in release 2.2 ***/ + /* Iterators */ + PyObject_SelfIter, /* getiterfunc tp_iter; */ (iternextfunc)pyrna_prop_collection_iter_next, /* iternextfunc tp_iternext; */ /*** Attribute descriptor and subclassing stuff ***/ @@ -7640,9 +7632,6 @@ void BPY_rna_init(void) /* For some reason MSVC complains of these. */ #if defined(_MSC_VER) pyrna_struct_meta_idprop_Type.tp_base = &PyType_Type; - - pyrna_prop_collection_iter_Type.tp_iter = PyObject_SelfIter; - pyrna_prop_collection_iter_Type.tp_getattro = PyObject_GenericGetAttr; #endif /* metaclass */ diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c index 3771cc05490..daab1631e8e 100644 --- a/source/blender/python/intern/bpy_rna_data.c +++ b/source/blender/python/intern/bpy_rna_data.c @@ -100,8 +100,8 @@ static PyTypeObject bpy_rna_data_context_Type = { NULL, /* reprfunc tp_str; */ /* will only use these if this is a subtype of a py class */ - NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ /* Functions to access object as input/output buffer */ NULL, /* PyBufferProcs *tp_as_buffer; */ -- cgit v1.2.3 From 960337f17abd3938f2c126d3a0a83aef8f6c354b Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Thu, 11 Mar 2021 13:42:37 +0100 Subject: Fix T86455: vertex color baking issue with sculpt vertex colors Baking to Vertex Colors would always bake to sculpt vertex colors (if such a layer is present) even if those are not enabled in the experimental preferences. This would bake without an error but leave the user without a result to look in the viewport. Now check if sculpt vertex colors are enabled and only bake to them in that case. Maniphest Tasks: T86455 Differential Revision: https://developer.blender.org/D10692 --- source/blender/editors/object/object_bake_api.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 610551e8539..d64769567f7 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -450,8 +450,9 @@ static bool bake_object_check(ViewLayer *view_layer, if (target == R_BAKE_TARGET_VERTEX_COLORS) { MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); + const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors); MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); - if (mcol == NULL && mloopcol == NULL) { + if (mloopcol == NULL && !mcol_valid) { BKE_reportf(reports, RPT_ERROR, "No vertex colors layer found in the object \"%s\"", @@ -933,8 +934,9 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re Mesh *me = ob->data; MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); + const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors); MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); - if (mcol == NULL && mloopcol == NULL) { + if (mloopcol == NULL && !mcol_valid) { BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to"); return false; } @@ -1043,6 +1045,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, { Mesh *me = ob->data; MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); + const bool mcol_valid = (mcol != NULL && U.experimental.use_sculpt_vertex_colors); MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); const int num_channels = targets->num_channels; const float *result = targets->result; @@ -1052,7 +1055,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, BLI_assert(me->totloop == me_split->totloop); UNUSED_VARS_NDEBUG(me_split); - if (mcol) { + if (mcol_valid) { const int totvert = me->totvert; const int totloop = me->totloop; -- cgit v1.2.3 From fd4c01a75c34fa88a20d3967d02996c0c9815efe Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 09:39:23 +0100 Subject: LibQuery: Add an option to process internal runtime ID pointers. In some cases (advanced, low-level code) we also want to process ID pointers like `ID.newid` or `ID.orig_id`. --- source/blender/blenkernel/BKE_lib_query.h | 10 ++++++++++ source/blender/blenkernel/intern/lib_query.c | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index f064d03261d..4e781aea9d3 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -70,6 +70,13 @@ enum { /** That ID is used as library override's reference by its owner. */ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5), + /** + * Indicates that this is an internal runtime ID pointer, like e.g. `ID.newid` or `ID.original`. + * \note Those should be ignored in most cases, and won't be processed/generated anyway unless + * `IDWALK_DO_INTERNAL_RUNTIME_POINTERS` option is enabled. + */ + IDWALK_CB_INTERNAL = (1 << 6), + /** * This ID usage is fully refcounted. * Callback is responsible to deal accordingly with #ID.us if needed. @@ -126,6 +133,9 @@ enum { IDWALK_IGNORE_EMBEDDED_ID = (1 << 3), IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */ + /** Also process internal ID pointers like `ID.newid` or `ID.orig_id`. + * WARNING: Dangerous, use with caution. */ + IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9), }; typedef struct LibraryForeachIDData LibraryForeachIDData; diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index acd0c10040c..e33743eb36b 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -183,8 +183,9 @@ static void library_foreach_ID_link(Main *bmain, BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain); if (flag & IDWALK_RECURSE) { - /* For now, recursion implies read-only. */ + /* For now, recursion implies read-only, and no internal pointers. */ flag |= IDWALK_READONLY; + flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS; data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); BLI_LINKSTACK_INIT(data.ids_todo); @@ -230,6 +231,7 @@ static void library_foreach_ID_link(Main *bmain, } if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY) && + (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) == 0 && (((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) == ((data.flag & IDWALK_INCLUDE_UI) == 0))) { /* Note that this is minor optimization, even in worst cases (like id being an object with @@ -250,6 +252,11 @@ static void library_foreach_ID_link(Main *bmain, /* Note: ID.lib pointer is purposefully fully ignored here... * We may want to add it at some point? */ + if (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) { + CALLBACK_INVOKE_ID(id->newid, IDWALK_CB_INTERNAL); + CALLBACK_INVOKE_ID(id->orig_id, IDWALK_CB_INTERNAL); + } + if (id->override_library != NULL) { CALLBACK_INVOKE_ID(id->override_library->reference, IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE); -- cgit v1.2.3 From 4781ab0969cdb4e39a2a9947f2b1a613b13b6235 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 09:41:00 +0100 Subject: IDRemap: Add option to also remap internal runtime ID pointers. In some cases (advanced, low-level), we also want to remap pointers like `ID.newid` or `ID.orig_id`. Only known case currently is `id_delete`, to avoid leaving potential access to freed memory. See next commit and T86501. --- source/blender/blenkernel/BKE_lib_remap.h | 7 +++++++ source/blender/blenkernel/intern/lib_remap.c | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index 6e81273b82b..705d2b030e5 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -78,6 +78,13 @@ enum { ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5, /** Don't touch the user count (use for low level actions such as swapping pointers). */ ID_REMAP_SKIP_USER_CLEAR = 1 << 6, + /** + * Force internal ID runtime pointers (like `ID.newid`, `ID.orig_id` etc.) to also be processed. + * This should only be needed in some very specific cases, typically only BKE ID management code + * should need it (e.g. required from `id_delete` to ensure no runtime pointer remains using + * freed ones). + */ + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS = 1 << 7, }; /* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 0218cb913a8..1f597bbb9a6 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -373,9 +373,12 @@ static void libblock_remap_data( Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data) { IDRemap id_remap_data; - const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? - IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : - IDWALK_NOP; + const int foreach_id_flags = ((remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? + IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : + IDWALK_NOP) | + ((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ? + IDWALK_DO_INTERNAL_RUNTIME_POINTERS : + IDWALK_NOP); if (r_id_remap_data == NULL) { r_id_remap_data = &id_remap_data; -- cgit v1.2.3 From fe2ceef729a1a1013f7a8466318a12343a6a0e15 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 09:43:17 +0100 Subject: Fix first part of T86501: Crash during resync process. Code would end up freeing some of the newly created overrides, which were assigned to the matching linked ID's `newid` pointer, accessed again further down the code. Note that this is not a normal expected situation, and it won't give a proper resync result anyway, but it might happen in some complicated corner cases, and also quite often when dealing with older .blend files. --- source/blender/blenkernel/intern/lib_id_delete.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 1d7f89e1e8d..67b2e4429d6 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -300,11 +300,15 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * links, this can lead to nasty crashing here in second, actual deleting loop. * Also, this will also flag users of deleted data that cannot be unlinked * (object using deleted obdata, etc.), so that they also get deleted. */ - BKE_libblock_remap_locked( - bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE); + BKE_libblock_remap_locked(bmain, + id, + NULL, + (ID_REMAP_FLAG_NEVER_NULL_USAGE | + ID_REMAP_FORCE_NEVER_NULL_USAGE | + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); /* Since we removed ID from Main, * we also need to unlink its own other IDs usages ourself. */ - BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0); + BKE_libblock_relink_ex(bmain, id, NULL, NULL, ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS); } } @@ -337,8 +341,12 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * actual deleting loop. * Also, this will also flag users of deleted data that cannot be unlinked * (object using deleted obdata, etc.), so that they also get deleted. */ - BKE_libblock_remap_locked( - bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE); + BKE_libblock_remap_locked(bmain, + id, + NULL, + (ID_REMAP_FLAG_NEVER_NULL_USAGE | + ID_REMAP_FORCE_NEVER_NULL_USAGE | + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); } } } -- cgit v1.2.3 From 74557ca4f7cfe14090d6ca245e03e651b4b2524f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 12:31:25 +0100 Subject: LibOverride: Add a new operation to Outliner to enforce resync of hierarchies. This is basically done by ignoring override operations from old override affecting ID pointer properties, when the new (destination) one is not NULL. Fix T86501: New object added to overridden collection doesn't show up in linking file on Resync. This is more of a work-around actually, since there is no real way to fix the issue in a fully automated and consistent way, it is caused by older blender files being saved with 'broken' overrides. WARNING: This cannot ensure that some purposedly edited/overridden ID pointer properties won't be lost in the process. --- source/blender/blenkernel/BKE_lib_override.h | 3 +- source/blender/blenkernel/intern/lib_override.c | 23 ++++++++++---- .../editors/space_outliner/outliner_tools.c | 33 ++++++++++++++++++-- source/blender/makesrna/RNA_access.h | 12 +++++++- .../makesrna/intern/rna_access_compare_override.c | 36 +++++++++++++++++++++- 5 files changed, 96 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index e548f778c71..ccb313f0e2a 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -79,7 +79,8 @@ bool BKE_lib_override_library_proxy_convert(struct Main *bmain, bool BKE_lib_override_library_resync(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, - struct ID *id_root); + struct ID *id_root, + const bool do_hierarchy_enforce); void BKE_lib_override_library_main_resync(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 5100fbf08ad..223ae13cba9 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -829,7 +829,8 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, * \param id_root: The root liboverride ID to resync from. * \return true if override was successfully resynced. */ -bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root) +bool BKE_lib_override_library_resync( + Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, const bool do_hierarchy_enforce) { BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); @@ -978,8 +979,14 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ } } - RNA_struct_override_apply( - bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library); + RNA_struct_override_apply(bmain, + &rnaptr_dst, + &rnaptr_src, + NULL, + id_override_new->override_library, + do_hierarchy_enforce ? + RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS : + RNA_OVERRIDE_APPLY_FLAG_NOP); } } } @@ -1144,7 +1151,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer * continue; } do_continue = true; - const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id); + const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id, false); CLOG_INFO(&LOG, 2, "Resynced %s, success: %d", id->name, success); break; } @@ -2104,8 +2111,12 @@ void BKE_lib_override_library_update(Main *bmain, ID *local) RNA_id_pointer_create(local->override_library->storage, rnaptr_storage); } - RNA_struct_override_apply( - bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_library); + RNA_struct_override_apply(bmain, + &rnaptr_dst, + &rnaptr_src, + rnaptr_storage, + local->override_library, + RNA_OVERRIDE_APPLY_FLAG_NOP); /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. * So when we'll free tmp_id, we'll actually free old, outdated data from local. */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 9af2ba6a82b..d9641930134 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -776,6 +776,11 @@ static void object_proxy_to_override_convert_fn(bContext *C, typedef struct OutlinerLibOverrideData { bool do_hierarchy; + /** + * For resync operation, force keeping newly created override IDs (or original linked IDs) + * instead of re-applying relevant existing ID pointer property override operations. Helps + * solving broken overrides while not losing *all* of your overrides. */ + bool do_resync_hierarchy_enforce; } OutlinerLibOverrideData; static void id_override_library_create_fn(bContext *C, @@ -872,10 +877,12 @@ static void id_override_library_resync_fn(bContext *C, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, - void *UNUSED(user_data)) + void *user_data) { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; + OutlinerLibOverrideData *data = user_data; + const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { Main *bmain = CTX_data_main(C); @@ -893,7 +900,8 @@ static void id_override_library_resync_fn(bContext *C, te->store_elem->id->tag |= LIB_TAG_DOIT; } - BKE_lib_override_library_resync(bmain, scene, CTX_data_view_layer(C), id_root); + BKE_lib_override_library_resync( + bmain, scene, CTX_data_view_layer(C), id_root, do_hierarchy_enforce); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1710,6 +1718,7 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE, OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, @@ -1770,6 +1779,13 @@ static const EnumPropertyItem prop_id_op_types[] = { "Resync Library Override Hierarchy", "Rebuild this local override from its linked reference, as well as its hierarchy of " "dependencies"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE, + "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE", + 0, + "Resync Library Override Hierarchy Enforce", + "Rebuild this local override from its linked reference, as well as its hierarchy of " + "dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting " + "overrides on data-blocks pointer properties)"}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, "OVERRIDE_LIBRARY_DELETE_HIERARCHY", 0, @@ -1831,6 +1847,7 @@ static bool outliner_id_operation_item_poll(bContext *C, case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: + case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) { return true; @@ -2041,6 +2058,18 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Resync Overridden Data Hierarchy"); break; } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: { + outliner_do_libdata_operation( + C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_resync_fn, + &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true}); + ED_undo_push(C, "Resync Overridden Data Hierarchy"); + break; + } case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: { outliner_do_libdata_operation(C, op->reports, diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 74b8517f538..4c60ffe4f16 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -1512,11 +1512,21 @@ bool RNA_struct_override_store(struct Main *bmain, PointerRNA *ptr_storage, struct IDOverrideLibrary *override); +typedef enum eRNAOverrideApplyFlag { + RNA_OVERRIDE_APPLY_FLAG_NOP = 0, + /** + * Hack to work around/fix older broken overrides: Do not apply override operations affecting ID + * pointers properties, unless the destination original value (the one being overridden) is NULL. + */ + RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0, +} eRNAOverrideApplyFlag; + void RNA_struct_override_apply(struct Main *bmain, struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage, - struct IDOverrideLibrary *override); + struct IDOverrideLibrary *override, + const eRNAOverrideApplyFlag flag); struct IDOverrideLibraryProperty *RNA_property_override_property_find(struct Main *bmain, PointerRNA *ptr, diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 6a8152d1139..28d4cc4d075 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -1123,7 +1123,8 @@ void RNA_struct_override_apply(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, - IDOverrideLibrary *override) + IDOverrideLibrary *override, + const eRNAOverrideApplyFlag flag) { #ifdef DEBUG_OVERRIDE_TIMEIT TIMEIT_START_AVERAGED(RNA_struct_override_apply); @@ -1187,6 +1188,39 @@ void RNA_struct_override_apply(Main *bmain, } } + /* Workaround for older broken overrides, we then assume that non-matching ID pointers + * override operations that replace a non-NULL value are 'mistakes', and ignore (do not + * apply) them. */ + if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) != 0 && + op->rna_prop_type == PROP_POINTER && + (((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag & + IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) { + BLI_assert(ptr_src->owner_id == + rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL)); + BLI_assert(ptr_dst->owner_id == + rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL)); + + PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst); + if (prop_ptr_dst.type != NULL && RNA_struct_is_ID(prop_ptr_dst.type)) { +#ifndef NDEBUG + PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src); + BLI_assert(prop_ptr_src.type == NULL || RNA_struct_is_ID(prop_ptr_src.type)); +#endif + ID *id_dst = rna_property_override_property_real_id_owner( + bmain, &prop_ptr_dst, NULL, NULL); + + if (id_dst != NULL) { + CLOG_INFO(&LOG, + 3, + "%s: Ignoring local override on ID pointer property '%s', as requested by " + "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag", + ptr_dst->owner_id->name, + op->rna_path); + continue; + } + } + } + rna_property_override_apply_ex(bmain, &data_dst, &data_src, -- cgit v1.2.3 From 583df9a5f82e0ed7c0836aee33945863b350e513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Mar 2021 13:19:24 +0100 Subject: Cleanup: document `FileSelectAssetLibraryUID::type` No functional changes. --- source/blender/makesdna/DNA_space_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 300956c28fd..0febbe26596 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -694,7 +694,7 @@ typedef enum eSpaceSeq_OverlayType { * custom library. Otherwise idname is not used. */ typedef struct FileSelectAssetLibraryUID { - short type; + short type; /* eFileAssetLibrary_Type */ char _pad[2]; /** * If showing a custom asset library (#FILE_ASSET_LIBRARY_CUSTOM), this is the index of the -- cgit v1.2.3 From 7388f9df7128963921740fe91a56ce8ee4c71fa7 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 12 Mar 2021 13:32:18 +0100 Subject: Cleanup: Compiler warnings with COM_TM_NOTHREAD active. --- source/blender/compositor/intern/COM_WorkScheduler.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc index a70b6ba4abe..f19c54991cd 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cc +++ b/source/blender/compositor/intern/COM_WorkScheduler.cc @@ -190,10 +190,10 @@ bool WorkScheduler::has_gpu_devices() # ifdef COM_OPENCL_ENABLED return !g_work_scheduler.gpu_devices.empty(); # else - return 0; + return false; # endif #else - return 0; + return false; #endif } -- cgit v1.2.3 From fd905c1059466f7f0f56ecc9d662af7231054735 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 12 Mar 2021 14:32:24 +0100 Subject: Cleanup: fix clang-tidy errors when COM_debug is active. --- source/blender/compositor/intern/COM_Debug.cc | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc index b49d575cade..bee3026816e 100644 --- a/source/blender/compositor/intern/COM_Debug.cc +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -56,9 +56,7 @@ std::string DebugInfo::node_name(const Node *node) if (it != m_node_names.end()) { return it->second; } - else { - return ""; - } + return ""; } std::string DebugInfo::operation_name(const NodeOperation *op) @@ -67,9 +65,7 @@ std::string DebugInfo::operation_name(const NodeOperation *op) if (it != m_op_names.end()) { return it->second; } - else { - return ""; - } + return ""; } void DebugInfo::convert_started() @@ -81,10 +77,8 @@ void DebugInfo::execute_started(const ExecutionSystem *system) { m_file_index = 1; m_group_states.clear(); - for (ExecutionSystem::Groups::const_iterator it = system->m_groups.begin(); - it != system->m_groups.end(); - ++it) { - m_group_states[*it] = EG_WAIT; + for (ExecutionGroup *execution_group : system->m_groups) { + m_group_states[execution_group] = EG_WAIT; } } @@ -355,10 +349,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n"); } - for (ExecutionGroup::Operations::const_iterator it = group->m_operations.begin(); - it != group->m_operations.end(); - ++it) { - NodeOperation *operation = *it; + for (NodeOperation *operation : group->m_operations) { sprintf(strbuf, "_%p", group); op_groups[operation].push_back(std::string(strbuf)); @@ -385,7 +376,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma op_groups[operation].push_back(std::string("")); - len += graphviz_operation(system, operation, 0, str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_operation( + system, operation, nullptr, str + len, maxlen > len ? maxlen - len : 0); } for (int i = 0; i < totops; i++) { @@ -452,7 +444,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma for (int l = 0; l < to_groups.size(); l++) { len += snprintf(str + len, maxlen > len ? maxlen - len : 0, - "\"O_%p%s\":\"OUT_%p\":e -> \"O_%p%s\":\"IN_%p\":w", + R"("O_%p%s":"OUT_%p":e -> "O_%p%s":"IN_%p":w)", from_op, from_groups[k].c_str(), from, -- cgit v1.2.3 From 20ee6c0f16e8eebd2afc2721f9c8ec1ac53f3a06 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 12 Mar 2021 15:12:09 +0100 Subject: Fix compiler warning when building Cycles without Embree --- intern/cycles/render/geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 9f8bf68dadf..de0e06828bc 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -1367,7 +1367,7 @@ void GeometryManager::device_update_bvh(Device *device, dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions(); /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */ - dscene->data.bvh.scene = NULL; + dscene->data.bvh.scene = 0; } /* Set of flags used to help determining what data has been modified or needs reallocation, so we -- cgit v1.2.3 From c7354cc64bdf9931ad61bb49f5513864d10b1ff0 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 15:25:20 +0100 Subject: Fix another crash in LibOverride resync code. Another case where newly overridden ID (stored in `newid` of its linked reference) gets immediately deleted in old broken overrides. Re T86501. --- source/blender/blenkernel/intern/lib_override.c | 86 +++++++++++++------------ 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 223ae13cba9..7a6e7a35724 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -650,53 +650,59 @@ static void lib_override_library_create_post_process( { BKE_main_collection_sync(bmain); - switch (GS(id_root->name)) { - case ID_GR: { - Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? - (Object *)id_reference : - NULL; - Collection *collection_new = ((Collection *)id_root->newid); - if (ob_reference != NULL) { - BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new); - } - else if (id_reference != NULL) { - BKE_collection_add_from_collection( - bmain, scene, ((Collection *)id_reference), collection_new); - } - else { - BKE_collection_add_from_collection(bmain, scene, ((Collection *)id_root), collection_new); - } + if (id_root->newid != NULL) { + switch (GS(id_root->name)) { + case ID_GR: { + Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? + (Object *)id_reference : + NULL; + Collection *collection_new = ((Collection *)id_root->newid); + if (ob_reference != NULL) { + BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new); + } + else if (id_reference != NULL) { + BLI_assert(GS(id_reference->name) == ID_GR); + BKE_collection_add_from_collection( + bmain, scene, ((Collection *)id_reference), collection_new); + } + else { + BKE_collection_add_from_collection( + bmain, scene, ((Collection *)id_root), collection_new); + } - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) { - if (ob_new != NULL && ob_new->id.override_library != NULL) { - if (ob_reference != NULL) { - Base *base; - if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { - BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new); - base = BKE_view_layer_base_find(view_layer, ob_new); - DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); - } + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) { + if (ob_new != NULL && ob_new->id.override_library != NULL) { + if (ob_reference != NULL) { + Base *base; + if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { + BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new); + base = BKE_view_layer_base_find(view_layer, ob_new); + DEG_id_tag_update_ex( + bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + } - if (ob_new == (Object *)ob_reference->id.newid) { - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); + if (ob_new == (Object *)ob_reference->id.newid) { + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + } + } + else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { + BKE_collection_object_add(bmain, collection_new, ob_new); + DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } - } - else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { - BKE_collection_object_add(bmain, collection_new, ob_new); - DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + break; } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - break; - } - case ID_OB: { - BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ((Object *)id_root->newid)); - break; + case ID_OB: { + BKE_collection_object_add_from( + bmain, scene, (Object *)id_root, ((Object *)id_root->newid)); + break; + } + default: + break; } - default: - break; } /* We need to ensure all new overrides of objects are properly instantiated. */ -- cgit v1.2.3 From f0c3ec3dc8bc0e361b47952bad105499a2d23fae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 13 Mar 2021 01:25:34 +1100 Subject: Fix T82532: Sculpt fails to redo the first sculpt session stroke Sculpt undo relied on having a mode-changing undo step to properly apply changes. However this isn't the case with startup files or when mixing global undo steps with sculpt (see T82851, also fixed). Undo stepping logic follows image_undosys_step_decode_undo. --- source/blender/editors/sculpt_paint/sculpt_undo.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index ec103bd2b98..b1e71a27dfc 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1492,7 +1492,8 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C, static void sculpt_undosys_step_decode_undo(struct bContext *C, Depsgraph *depsgraph, - SculptUndoStep *us) + SculptUndoStep *us, + const bool is_final) { SculptUndoStep *us_iter = us; while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { @@ -1501,8 +1502,12 @@ static void sculpt_undosys_step_decode_undo(struct bContext *C, } us_iter = (SculptUndoStep *)us_iter->step.next; } - while (us_iter != us) { + + while ((us_iter != us) || (!is_final && us_iter == us)) { sculpt_undosys_step_decode_undo_impl(C, depsgraph, us_iter); + if (us_iter == us) { + break; + } us_iter = (SculptUndoStep *)us_iter->step.prev; } } @@ -1527,11 +1532,8 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C, } } -static void sculpt_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - const eUndoStepDir dir, - bool UNUSED(is_final)) +static void sculpt_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final) { BLI_assert(dir != STEP_INVALID); @@ -1574,7 +1576,7 @@ static void sculpt_undosys_step_decode(struct bContext *C, SculptUndoStep *us = (SculptUndoStep *)us_p; if (dir == STEP_UNDO) { - sculpt_undosys_step_decode_undo(C, depsgraph, us); + sculpt_undosys_step_decode_undo(C, depsgraph, us, is_final); } else if (dir == STEP_REDO) { sculpt_undosys_step_decode_redo(C, depsgraph, us); -- cgit v1.2.3 From bcac17196a90967b78013aefd89bf547cf8e694c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 12 Mar 2021 15:58:58 +0100 Subject: Fix heap buffer overflow appending/linking from a blend file Add new function `blo_bhead_is_id_valid_type()` to correctly check the blend file block type. File block type codes have four bytes, and two of those are only in use when these blocks contain ID datablocks (like `"OB\0\0"`). However, there are other types defined in `BLO_blend_defs.h` that have four bytes, like `TEST`, `ENDB`, etc. The function `BKE_idtype_idcode_is_valid(short idcode)` was used to check for ID datablocks while reading a blend file. This only takes a 2-byte parameter, and thus its result is invalid for the 4-byte codes. For `TEST` blocks, it would actually consider it a `TE` block, which is a valid identifier for a Texture. This caused the heap buffer overflow, as the datablock is not a valid ID, and thus the bytes that were expected to form an ID name actually encode something completely different. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D10703 --- source/blender/blenloader/intern/readfile.c | 33 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 302abf35f1c..e809b22cdbf 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -555,6 +555,23 @@ static void read_file_version(FileData *fd, Main *main) } } +static bool blo_bhead_is_id(BHead *bhead) +{ + /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes + * are zero, the values actually indicate an ID type. */ + return bhead->code <= 0xFFFF; +} + +static bool blo_bhead_is_id_valid_type(BHead *bhead) +{ + if (!blo_bhead_is_id(bhead)) { + return false; + } + + const short id_type_code = bhead->code & 0xFFFF; + return BKE_idtype_idcode_is_valid(id_type_code); +} + #ifdef USE_GHASH_BHEAD static void read_file_bhead_idname_map_create(FileData *fd) { @@ -568,8 +585,9 @@ static void read_file_bhead_idname_map_create(FileData *fd) for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { if (code_prev != bhead->code) { code_prev = bhead->code; - is_link = BKE_idtype_idcode_is_valid(code_prev) ? BKE_idtype_idcode_is_linkable(code_prev) : - false; + is_link = blo_bhead_is_id_valid_type(bhead) ? + BKE_idtype_idcode_is_linkable((short)code_prev) : + false; } if (is_link) { @@ -584,8 +602,9 @@ static void read_file_bhead_idname_map_create(FileData *fd) for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { if (code_prev != bhead->code) { code_prev = bhead->code; - is_link = BKE_idtype_idcode_is_valid(code_prev) ? BKE_idtype_idcode_is_linkable(code_prev) : - false; + is_link = blo_bhead_is_id_valid_type(bhead) ? + BKE_idtype_idcode_is_linkable((short)code_prev) : + false; } if (is_link) { @@ -973,7 +992,7 @@ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) /* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) { - BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + BLI_assert(blo_bhead_is_id_valid_type(bhead)); return (fd->id_asset_data_offset >= 0) ? *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) : NULL; @@ -3711,7 +3730,7 @@ static BHead *read_libblock(FileData *fd, BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data) { - BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + BLI_assert(blo_bhead_is_id_valid_type(bhead)); bhead = read_data_into_datamap(fd, bhead, "asset-data read"); @@ -4923,7 +4942,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_t break; } - if (BKE_idtype_idcode_is_valid(bhead->code) && BKE_idtype_idcode_is_linkable(bhead->code) && + if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) && (id_types_mask == 0 || (BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) { read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id); -- cgit v1.2.3 From ef5782e297449e00e5c82e025552ddfa5cd223b2 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 15:38:31 +0100 Subject: CLOG: add support for substring matching. So that `--log "*undo*"` matches any log identifier containing `undo`. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D10647 --- intern/clog/clog.c | 14 +++++++++++--- source/creator/creator_args.c | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/intern/clog/clog.c b/intern/clog/clog.c index a26ac10a61f..391b71d77de 100644 --- a/intern/clog/clog.c +++ b/intern/clog/clog.c @@ -303,19 +303,27 @@ static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity) * - `foo` exact match of `foo`. * - `foo.bar` exact match for `foo.bar` * - `foo.*` match for `foo` & `foo.bar` & `foo.bar.baz` + * - `*bar*` match for `foo.bar` & `baz.bar` & `foo.barbaz` * - `*` matches everything. */ static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier) { - const int identifier_len = strlen(identifier); + const size_t identifier_len = strlen(identifier); for (uint i = 0; i < 2; i++) { const CLG_IDFilter *flt = ctx->filters[i]; while (flt != NULL) { - const int len = strlen(flt->match); + const size_t len = strlen(flt->match); if (STREQ(flt->match, "*") || ((len == identifier_len) && (STREQ(identifier, flt->match)))) { return (bool)i; } - if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) { + if (flt->match[0] == '*' && flt->match[len - 1] == '*') { + char *match = MEM_callocN(sizeof(char) * len - 1, __func__); + memcpy(match, flt->match + 1, len - 2); + if (strstr(identifier, match) != NULL) { + return (bool)i; + } + } + else if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) { if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) || ((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1))) { return (bool)i; diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 0e0d66d40a9..7316c1729f5 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -869,6 +869,8 @@ static const char arg_handle_log_set_doc[] = "\tEnable logging categories, taking a single comma separated argument.\n" "\tMultiple categories can be matched using a '.*' suffix,\n" "\tso '--log \"wm.*\"' logs every kind of window-manager message.\n" + "\tSub-string can be matched using a '*' prefix and suffix,\n" + "\tso '--log \"*undo*\"' logs every kind of undo-related message.\n" "\tUse \"^\" prefix to ignore, so '--log \"*,^wm.operator.*\"' logs all except for " "'wm.operators.*'\n" "\tUse \"*\" to log everything."; -- cgit v1.2.3 From f707783d5f9fedbe2503d841bc8a74bed6092cdb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 12 Mar 2021 16:45:45 +0100 Subject: LibOverride Auto Resync: Add option to disable it in Experimental userpref. Some older .blend files won't react nicely to auto-resync, they need to get manually fixed with `resync enforce` first. --- release/scripts/startup/bl_ui/space_userpref.py | 1 + source/blender/blenkernel/intern/blendfile.c | 2 +- source/blender/makesdna/DNA_userdef_types.h | 3 ++- source/blender/makesrna/intern/rna_userdef.c | 8 ++++++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index b214dc0c245..5fcd84d119f 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2269,6 +2269,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): self._draw_items( context, ( ({"property": "use_undo_legacy"}, "T60695"), + ({"property": "override_auto_resync"}, "T83811"), ({"property": "use_cycles_debug"}, None), ), ) diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index d3dfe60c444..967eb81026c 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -395,7 +395,7 @@ static void setup_app_data(bContext *C, BKE_main_id_refcount_recompute(bmain, false); } - if (mode != LOAD_UNDO) { + if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { BKE_lib_override_library_main_resync( bmain, curscene, diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index bd8f3cd95a7..233c476cbf2 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -635,6 +635,7 @@ typedef struct UserDef_FileSpaceData { typedef struct UserDef_Experimental { /* Debug options, always available. */ char use_undo_legacy; + char no_override_auto_resync; char use_cycles_debug; char SANITIZE_AFTER_HERE; /* The following options are automatically sanitized (set to 0) @@ -645,7 +646,7 @@ typedef struct UserDef_Experimental { char use_switch_object_operator; char use_sculpt_tools_tilt; char use_asset_browser; - char _pad[7]; + char _pad[6]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4097e2dddea..e07d46dbe3e 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6245,6 +6245,14 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Undo Legacy", "Use legacy undo (slower than the new default one, but may be more stable in some cases)"); + prop = RNA_def_property(srna, "override_auto_resync", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "no_override_auto_resync", 1); + RNA_def_property_ui_text( + prop, + "Override Auto Resync", + "Enable library overrides automatic resync detection and process on file load. Disable when " + "dealing with older .blend files that need manual Resync (Enforce) handling"); + prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1); RNA_def_property_ui_text( -- cgit v1.2.3 From 651fe243e6dcb31e9838f5816eaa00206309f59c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 13 Mar 2021 03:14:41 +1100 Subject: Cleanup: const warning --- source/blender/blenloader/intern/readfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e809b22cdbf..347ee1378a4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -555,14 +555,14 @@ static void read_file_version(FileData *fd, Main *main) } } -static bool blo_bhead_is_id(BHead *bhead) +static bool blo_bhead_is_id(const BHead *bhead) { /* BHead codes are four bytes (like 'ENDB', 'TEST', etc.), but if the two most-significant bytes * are zero, the values actually indicate an ID type. */ return bhead->code <= 0xFFFF; } -static bool blo_bhead_is_id_valid_type(BHead *bhead) +static bool blo_bhead_is_id_valid_type(const BHead *bhead) { if (!blo_bhead_is_id(bhead)) { return false; -- cgit v1.2.3 From abe1a061f8aab5c9357ff92fd6b579a8a9553f0d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 13 Mar 2021 03:12:24 +1100 Subject: Docs: add doc-string for TransDataContainer --- source/blender/editors/transform/transform.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 24335b6b6b7..4b43592165b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -429,6 +429,20 @@ typedef struct TransCustomDataContainer { } TransCustomDataContainer; #define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(TransCustomDataContainer) / sizeof(TransCustomData)) +/** + * Container for Transform Data + * + * Used to implement multi-object modes, so each object can have it's + * own data array as well as object matrix, local center etc. + * + * Anything that can't be shared between all objects + * and doesn't make sense to store for every vertex (in the #TransDataContainer.data). + * + * \note at some point this could be used to store non object containers + * although this only makes sense if each container has it's own matrices, + * otherwise all elements may as well be stored in one array (#TransDataContainer.data), + * as is already done for curve-objects, f-curves. etc. + */ typedef struct TransDataContainer { /** Transformed data (array). */ TransData *data; -- cgit v1.2.3 From b01e9ad4f0e34f83c582d1a3c1e3c90f2586dcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Fri, 12 Mar 2021 12:29:48 +0100 Subject: Fluid: Enable scale options for fluid particles There is no reason to hide the 'Scale' and 'Scale Randomness' options for fluid particles that are rendered as 'Object'. It is possible that hiding these options was just an oversight and not intentional. --- release/scripts/startup/bl_ui/properties_particle.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 60caa39b723..a9f040db9b5 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -1263,6 +1263,8 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): if ( part.type == 'EMITTER' or + part.type in {'FLIP', 'SPRAY', 'BUBBLE', 'FOAM', 'TRACER', + 'SPRAYFOAM', 'SPRAYBUBBLE', 'FOAMBUBBLE', 'SPRAYFOAMBUBBLE'} or (part.render_type in {'OBJECT', 'COLLECTION'} and part.type == 'HAIR') ): if part.render_type != 'NONE': -- cgit v1.2.3 From 476be3746e85b4891189c8d480501905b9400c66 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 12 Mar 2021 16:33:13 +0100 Subject: Fix T86332: setting Cycles dicing camera fails after recent changes Somehow "from __future__ import annotations" and "lambda" are not working together well here, work around it by not using a lambda function. --- intern/cycles/blender/addon/properties.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index dc4437bdc52..91bc1cb84a4 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -226,6 +226,9 @@ def update_render_passes(self, context): view_layer = context.view_layer view_layer.update_render_passes() +def poll_object_is_camera(self, obj): + return obj.type == 'CAMERA' + class CyclesRenderSettings(bpy.types.PropertyGroup): @@ -538,7 +541,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Camera to use as reference point when subdividing geometry, useful to avoid crawling " "artifacts in animations when the scene camera is moving", type=bpy.types.Object, - poll=lambda self, obj: obj.type == 'CAMERA', + poll=poll_object_is_camera, ) offscreen_dicing_scale: FloatProperty( name="Offscreen Dicing Scale", -- cgit v1.2.3 From 5788f608d391f1324a638a36fdf20eee75fbfac7 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Fri, 12 Mar 2021 19:12:11 +0100 Subject: GPencil: UI menu cleanup Remove duplicate words Stroke and Point already in menu header. Reviewed by: @mendio, @filedescriptor --- release/scripts/startup/bl_ui/space_view3d.py | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 4b687945974..19bf0662885 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -5013,7 +5013,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu): layout.menu("GPENCIL_MT_move_to_layer") layout.menu("VIEW3D_MT_assign_material") layout.operator("gpencil.set_active_material", text="Set as Active Material") - layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes") + layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange") layout.separator() @@ -5024,7 +5024,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu): layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE' layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps", property="type") layout.operator("gpencil.stroke_flip", text="Switch Direction") - layout.prop(settings, "use_scale_thickness") + layout.prop(settings, "use_scale_thickness", text="Scale Thickness") layout.separator() layout.operator("gpencil.reset_transform_fill", text="Reset Fill Transform") @@ -5036,15 +5036,15 @@ class VIEW3D_MT_edit_gpencil_point(Menu): def draw(self, _context): layout = self.layout - layout.operator("gpencil.extrude_move", text="Extrude Points") + layout.operator("gpencil.extrude_move", text="Extrude") layout.separator() - layout.operator("gpencil.stroke_smooth", text="Smooth Points").only_selected = True + layout.operator("gpencil.stroke_smooth", text="Smooth").only_selected = True layout.separator() - layout.operator("gpencil.stroke_merge", text="Merge Points") + layout.operator("gpencil.stroke_merge", text="Merge") # TODO: add new RIP operator @@ -7048,12 +7048,12 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.separator() - col.operator("gpencil.extrude_move", text="Extrude Points") + col.operator("gpencil.extrude_move", text="Extrude") col.separator() # Deform Operators - col.operator("gpencil.stroke_smooth", text="Smooth Points").only_selected = True + col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = True col.operator("transform.bend", text="Bend") col.operator("transform.shear", text="Shear") col.operator("transform.tosphere", text="To Sphere") @@ -7061,8 +7061,8 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.separator() - col.menu("VIEW3D_MT_mirror", text="Mirror Points") - col.menu("GPENCIL_MT_snap", text="Snap Points") + col.menu("VIEW3D_MT_mirror", text="Mirror") + col.menu("GPENCIL_MT_snap", text="Snap") col.separator() @@ -7075,15 +7075,15 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.separator() # Removal Operators - col.operator("gpencil.stroke_merge", text="Merge Points") + col.operator("gpencil.stroke_merge", text="Merge") col.operator("gpencil.stroke_merge_by_distance").use_unselected = False col.operator("gpencil.stroke_split", text="Split") col.operator("gpencil.stroke_separate", text="Separate").mode = 'POINT' col.separator() - col.operator("gpencil.delete", text="Delete Points").type = 'POINTS' - col.operator("gpencil.dissolve", text="Dissolve Points").type = 'POINTS' + col.operator("gpencil.delete", text="Delete").type = 'POINTS' + col.operator("gpencil.dissolve", text="Dissolve").type = 'POINTS' col.operator("gpencil.dissolve", text="Dissolve Between").type = 'BETWEEN' col.operator("gpencil.dissolve", text="Dissolve Unselected").type = 'UNSELECT' @@ -7100,7 +7100,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.separator() - col.operator("gpencil.stroke_smooth", text="Smooth Stroke").only_selected = False + col.operator("gpencil.stroke_smooth", text="Smooth").only_selected = False col.operator("transform.transform", text="Shrink/Fatten").mode = 'GPENCIL_SHRINKFATTEN' col.separator() @@ -7109,12 +7109,12 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.menu("GPENCIL_MT_move_to_layer") col.menu("VIEW3D_MT_assign_material") col.operator("gpencil.set_active_material", text="Set as Active Material") - col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes") + col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange") col.separator() - col.menu("VIEW3D_MT_mirror", text="Mirror Stroke") - col.menu("VIEW3D_MT_snap", text="Snap Stroke") + col.menu("VIEW3D_MT_mirror", text="Mirror") + col.menu("VIEW3D_MT_snap", text="Snap") col.separator() @@ -7134,11 +7134,11 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu): col.separator() - col.operator("gpencil.delete", text="Delete Strokes").type = 'STROKES' + col.operator("gpencil.delete", text="Delete").type = 'STROKES' col.separator() - col.operator("gpencil.reproject", text="Reproject Strokes") + col.operator("gpencil.reproject", text="Reproject") def draw_gpencil_layer_active(context, layout): -- cgit v1.2.3 From 9d08c169d1d540553f879afaecf7f06965a81469 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Fri, 12 Mar 2021 19:43:13 +0100 Subject: GPencil: Interpolate can use all keyframe types except breakdown Before only it was only possible interpolate frames of `Keyframe` type. Now all types except `Breakdown` can be used. `Breakdown` cannot be used because it would be impossible interpolate two times because the extremes of the interpolation would change and the clean operator would not work. --- source/blender/editors/gpencil/gpencil_interpolate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 3b7c80cee07..1281f1392d8 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -435,16 +435,16 @@ static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgp WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } -/* Helper: Get previous keyframe. */ +/* Helper: Get previous keyframe (exclude breakdown type). */ static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra) { if (gpl->actframe != NULL && gpl->actframe->framenum < cfra && - gpl->actframe->key_type == BEZT_KEYTYPE_KEYFRAME) { + gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN) { return gpl->actframe; } LISTBASE_FOREACH_BACKWARD (bGPDframe *, gpf, &gpl->frames) { - if (gpf->key_type != BEZT_KEYTYPE_KEYFRAME) { + if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) { continue; } if (gpf->framenum >= cfra) { @@ -456,11 +456,11 @@ static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra) return NULL; } -/* Helper: Get next keyframe. */ +/* Helper: Get next keyframe (exclude breakdown type). */ static bGPDframe *gpencil_get_next_keyframe(bGPDlayer *gpl, int cfra) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - if (gpf->key_type != BEZT_KEYTYPE_KEYFRAME) { + if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) { continue; } if (gpf->framenum <= cfra) { @@ -760,7 +760,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent Scene *scene = CTX_data_scene(C); tGPDinterpolate *tgpi = NULL; - /* cannot interpolate if not between 2 frames */ + /* Cannot interpolate if not between 2 frames. */ int cfra = CFRA; bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra); bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra); @@ -768,7 +768,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent BKE_report( op->reports, RPT_ERROR, - "Cannot find a pair of grease pencil frames to interpolate between in active layer"); + "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)"); return OPERATOR_CANCELLED; } @@ -1260,7 +1260,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) BKE_report( op->reports, RPT_ERROR, - "Cannot find a pair of grease pencil frames to interpolate between in active layer"); + "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)"); return OPERATOR_CANCELLED; } -- cgit v1.2.3 From 74052a9f02a1f891300bb1e36b98556c5f7820b2 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Fri, 12 Mar 2021 21:35:56 +0100 Subject: Sculpt: Mask Init operator This operator initializes mask values for the entire mesh. It supports different modes for initializing those values, and more will be added in the future. The initial version supports generating a random mask per vertex, Face Sets or loose parts. These masks are useful for introducing variations in the model using the filters (both shapes and colors). Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D10679 --- release/scripts/startup/bl_ui/space_view3d.py | 21 +++ source/blender/editors/sculpt_paint/CMakeLists.txt | 1 + source/blender/editors/sculpt_paint/sculpt.c | 1 + .../blender/editors/sculpt_paint/sculpt_intern.h | 6 + .../editors/sculpt_paint/sculpt_mask_init.c | 196 +++++++++++++++++++++ 5 files changed, 225 insertions(+) create mode 100644 source/blender/editors/sculpt_paint/sculpt_mask_init.c diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 19bf0662885..e393ddf16d6 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3121,6 +3121,11 @@ class VIEW3D_MT_mask(Menu): props = layout.operator("sculpt.dirty_mask", text='Dirty Mask') + layout.separator() + + layout.menu("VIEW3D_MT_random_mask", text="Random Mask") + + class VIEW3D_MT_face_sets(Menu): bl_label = "Face Sets" @@ -3222,6 +3227,21 @@ class VIEW3D_MT_face_sets_init(Menu): op.mode = 'FACE_MAPS' +class VIEW3D_MT_random_mask(Menu): + bl_label = "Random Mask" + + def draw(self, _context): + layout = self.layout + + op = layout.operator("sculpt.mask_init", text='Per Vertex') + op.mode = 'RANDOM_PER_VERTEX' + + op = layout.operator("sculpt.mask_init", text='Per Face Set') + op.mode = 'RANDOM_PER_FACE_SET' + + op = layout.operator("sculpt.mask_init", text='Per Loose Part') + op.mode = 'RANDOM_PER_LOOSE_PART' + class VIEW3D_MT_particle(Menu): bl_label = "Particle" @@ -7563,6 +7583,7 @@ classes = ( VIEW3D_MT_mask, VIEW3D_MT_face_sets, VIEW3D_MT_face_sets_init, + VIEW3D_MT_random_mask, VIEW3D_MT_particle, VIEW3D_MT_particle_context_menu, VIEW3D_MT_particle_showhide, diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index fff172c0707..3b668a1bd4c 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC sculpt_filter_mesh.c sculpt_geodesic.c sculpt_mask_expand.c + sculpt_mask_init.c sculpt_multiplane_scrape.c sculpt_paint_color.c sculpt_pose.c diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 0b30303de91..d32391bfb67 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -9461,6 +9461,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_color_filter); WM_operatortype_append(SCULPT_OT_mask_by_color); WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); + WM_operatortype_append(SCULPT_OT_mask_init); WM_operatortype_append(SCULPT_OT_expand); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index c323a4d744a..087cb6dd94a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -792,6 +792,9 @@ typedef struct SculptThreadedTaskData { int face_set; int filter_undo_type; + int mask_init_mode; + int mask_init_seed; + ThreadMutex mutex; } SculptThreadedTaskData; @@ -1356,6 +1359,9 @@ void SCULPT_OT_dirty_mask(struct wmOperatorType *ot); /* Mask and Face Sets Expand. */ void SCULPT_OT_mask_expand(struct wmOperatorType *ot); +/* Mask Init. */ +void SCULPT_OT_mask_init(struct wmOperatorType *ot); + /* Detail size. */ void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot); void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c new file mode 100644 index 00000000000..b2fae9198fd --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -0,0 +1,196 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_hash.h" +#include "BLI_task.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_context.h" +#include "BKE_mesh.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_sculpt.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "bmesh.h" + +#include +#include + +/* Mask Init operator. */ +/* Initializes mask values for the entire mesh depending on the mode. */ + +typedef enum eSculptMaskInitMode { + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + SCULPT_MASK_INIT_RANDOM_PER_FACE_SET, + SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART, +} eSculptMaskInitMode; + +static EnumPropertyItem prop_sculpt_mask_init_mode_types[] = { + { + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + "RANDOM_PER_VERTEX", + 0, + "Random per Vertex", + "", + }, + { + SCULPT_MASK_INIT_RANDOM_PER_FACE_SET, + "RANDOM_PER_FACE_SET", + 0, + "Random per Face Set", + "", + }, + { + SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART, + "RANDOM_PER_LOOSE_PART", + 0, + "Random per Loose Part", + "", + }, + {0, NULL, 0, NULL, NULL}, +}; + +static void mask_init_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + PBVHVertexIter vd; + const int mode = data->mask_init_mode; + const int seed = data->mask_init_seed; + SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + switch (mode) { + case SCULPT_MASK_INIT_RANDOM_PER_VERTEX: + *vd.mask = BLI_hash_int_01(vd.index + seed); + break; + case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: { + const int face_set = SCULPT_vertex_face_set_get(ss, vd.index); + *vd.mask = BLI_hash_int_01(face_set + seed); + break; + } + case SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART: + *vd.mask = BLI_hash_int_01(ss->vertex_info.connected_component[vd.index] + seed); + break; + } + } + BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_update_mask(data->nodes[i]); +} + +static int sculpt_mask_init_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + + const int mode = RNA_enum_get(op->ptr, "mode"); + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + PBVH *pbvh = ob->sculpt->pbvh; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + + if (totnode == 0) { + return OPERATOR_CANCELLED; + } + + SCULPT_undo_push_begin(ob, "init mask"); + + if (mode == SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART) { + SCULPT_connected_components_ensure(ob); + } + + SculptThreadedTaskData data = { + .ob = ob, + .nodes = nodes, + .mask_init_mode = mode, + .mask_init_seed = PIL_check_seconds_timer(), + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, mask_init_task_cb, &settings); + + multires_stitch_grids(ob); + + SCULPT_undo_push_end(); + + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + MEM_SAFE_FREE(nodes); + SCULPT_tag_update_overlays(C); + return OPERATOR_FINISHED; +} + +void SCULPT_OT_mask_init(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Init Mask"; + ot->description = "Creates a new mask for the entire mesh"; + ot->idname = "SCULPT_OT_mask_init"; + + /* api callbacks */ + ot->exec = sculpt_mask_init_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + RNA_def_enum(ot->srna, + "mode", + prop_sculpt_mask_init_mode_types, + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + "Mode", + ""); +} -- cgit v1.2.3 From 258b15da74ad6f734d4e9870bbe051066a9a705c Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Fri, 12 Mar 2021 22:20:51 +0100 Subject: Cleanup: add BKE_pbvh_vertex_iter_begin to clang-format Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D10707 --- .clang-format | 1 + source/blender/blenkernel/intern/pbvh.c | 9 +- source/blender/editors/sculpt_paint/paint_mask.c | 12 +-- source/blender/editors/sculpt_paint/paint_vertex.c | 24 ++--- source/blender/editors/sculpt_paint/sculpt.c | 105 +++++++-------------- .../blender/editors/sculpt_paint/sculpt_boundary.c | 18 ++-- source/blender/editors/sculpt_paint/sculpt_cloth.c | 12 +-- .../blender/editors/sculpt_paint/sculpt_expand.c | 12 +-- .../blender/editors/sculpt_paint/sculpt_face_set.c | 6 +- .../editors/sculpt_paint/sculpt_filter_color.c | 3 +- .../editors/sculpt_paint/sculpt_filter_mask.c | 9 +- .../editors/sculpt_paint/sculpt_filter_mesh.c | 6 +- .../editors/sculpt_paint/sculpt_mask_expand.c | 9 +- .../editors/sculpt_paint/sculpt_mask_init.c | 5 +- .../sculpt_paint/sculpt_multiplane_scrape.c | 6 +- .../editors/sculpt_paint/sculpt_paint_color.c | 15 +-- source/blender/editors/sculpt_paint/sculpt_pose.c | 9 +- .../blender/editors/sculpt_paint/sculpt_smooth.c | 12 +-- .../editors/sculpt_paint/sculpt_transform.c | 9 +- source/blender/editors/sculpt_paint/sculpt_undo.c | 15 +-- 20 files changed, 100 insertions(+), 197 deletions(-) diff --git a/.clang-format b/.clang-format index 8a992fea3a9..79aa893cada 100644 --- a/.clang-format +++ b/.clang-format @@ -161,6 +161,7 @@ PenaltyBreakString: 1000000 # "^\s+[A-Z][A-Z0-9_]+\s*\([^\n]*\)\n\s*\{" ForEachMacros: - BEGIN_ANIMFILTER_SUBCHANNELS + - BKE_pbvh_vertex_iter_begin - BLI_FOREACH_SPARSE_RANGE - BLI_SMALLSTACK_ITER_BEGIN - BMO_ITER diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 8a98780d918..77dde3a921a 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -137,8 +137,7 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node) if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) { BB_expand(&vb, vd.co); } BKE_pbvh_vertex_iter_end; @@ -1143,8 +1142,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata, if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) { if (vd.mask && *vd.mask < 1.0f) { has_unmasked = true; } @@ -1191,8 +1189,7 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata, BKE_pbvh_node_fully_hidden_set(node, true); if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_ALL) { if (vd.visible) { BKE_pbvh_node_fully_hidden_set(node, false); return; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 966f2ace931..7671f69ee05 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -131,8 +131,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata, SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (data->pbvh, node, vi, PBVH_ITER_UNIQUE) { float prevmask = *vi.mask; mask_flood_fill_set_elem(vi.mask, mode, value); if (prevmask != *vi.mask) { @@ -757,8 +756,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata, PBVHVertexIter vd; bool any_updated = false; - BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id); any_updated = true; @@ -832,8 +830,7 @@ static void mask_gesture_apply_task_cb(void *__restrict userdata, bool any_masked = false; bool redraw = false; - BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { float prevmask = *vd.mask; if (!any_masked) { @@ -1415,8 +1412,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata, SCULPT_undo_push_node(sgcontext->vc.obact, node, SCULPT_UNDO_COORDS); - BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (!sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { continue; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index f45c244f675..fc52f6fea7c 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1841,8 +1841,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop corresponds to the current grid. @@ -1938,8 +1937,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop corresponds to the current grid. @@ -2045,8 +2043,7 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* Note: grids are 1:1 with corners (aka loops). @@ -2114,8 +2111,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) : @@ -2810,8 +2806,7 @@ static void do_vpaint_brush_calc_average_color_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { const int v_index = has_grids ? data->me->mloop[vd.grid_indices[vd.g]].v : @@ -2880,8 +2875,7 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* Note: Grids are 1:1 with corners (aka loops). @@ -2979,8 +2973,7 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop corresponds to the current grid. @@ -3103,8 +3096,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata, /* For each vertex */ PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* For grid based pbvh, take the vert whose loop corresponds to the current grid. diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index d32391bfb67..964e5bdaa90 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -970,8 +970,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, NearestVertexTLSData *nvtd = tls->userdata_chunk; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { @@ -1488,8 +1487,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, SCULPT_orig_vert_data_unode_init(&orig_data, data->ob, unode); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (orig_data.unode->type == SCULPT_UNDO_COORDS) { @@ -2050,8 +2048,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, } } else { - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float co[3]; /* For bm_vert only. */ @@ -2922,8 +2919,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -2995,8 +2991,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -3072,8 +3067,7 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -3138,8 +3132,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -3219,8 +3212,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex( SculptSession *ss = data->ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sub_v3_v3v3(ss->cache->prev_displacement[vd.index], SCULPT_vertex_co_get(ss, vd.index), ss->cache->limit_surface_co[vd.index]); @@ -3283,8 +3275,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -3362,8 +3353,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; @@ -3445,8 +3435,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; @@ -3603,8 +3592,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; @@ -3770,8 +3758,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -3888,8 +3875,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, copy_v3_v3(x_object_space, stroke_xz[0]); copy_v3_v3(z_object_space, stroke_xz[1]); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -4003,8 +3989,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { @@ -4105,8 +4090,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, BKE_kelvinlet_init_params( ¶ms, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float final_disp[3]; switch (brush->elastic_deform_type) { @@ -4336,8 +4320,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -4416,8 +4399,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, KelvinletParams params; BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -4554,8 +4536,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { @@ -4628,8 +4609,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { @@ -4701,8 +4681,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { @@ -4816,8 +4795,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -4922,8 +4900,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5029,8 +5006,7 @@ static void calc_clay_surface_task_cb(void *__restrict userdata, return; } - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5080,8 +5056,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5200,8 +5175,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { continue; } @@ -5354,8 +5328,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5453,8 +5426,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5568,8 +5540,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, /* Tilted plane (front part of the brush). */ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -5724,8 +5695,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -6236,8 +6206,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata, BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float val[3]; if (use_orco) { @@ -6332,8 +6301,7 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata, PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_flush_pbvhvert_deform(ob, &vd); if (!vertCos) { @@ -8917,8 +8885,7 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata, NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index); if (vd_topology_id != nvtd->current_topology_id && ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) { @@ -9188,8 +9155,7 @@ static void do_mask_by_color_contiguous_update_nodes_cb( const bool preserve_mask = data->mask_by_color_preserve_mask; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { const float current_mask = *vd.mask; const float new_mask = data->mask_by_color_floodfill[vd.index]; *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); @@ -9295,8 +9261,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { const float current_mask = *vd.mask; const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert); *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index f79621ccffd..37678ec276a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -667,8 +667,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, } const float angle = angle_factor * M_PI; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } @@ -716,8 +715,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } @@ -763,8 +761,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } @@ -810,8 +807,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } @@ -862,8 +858,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, } const float angle = angle_factor * M_PI; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } @@ -909,8 +904,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].num_propagation_steps == -1) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 16d10f6d6bb..a53a2126af4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -377,8 +377,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( data->cloth_sim_radius * data->cloth_sim_radius : FLT_MAX; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { const float len_squared = len_squared_v3v3(vd.co, data->cloth_sim_initial_location); if (len_squared < cloth_sim_radius_squared) { @@ -518,8 +517,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, madd_v3_v3fl(gravity, ss->cache->gravity_direction, -data->sd->gravity_factor); } - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float force[3]; float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); @@ -783,8 +781,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); const float sim_factor = @@ -1449,8 +1446,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float fade = vd.mask ? *vd.mask : 0.0f; fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); fade = 1.0f - fade; diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index db6d33c2700..8b8ed42a694 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -1143,8 +1143,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { copy_v4_v4(vd.col, expand_cache->original_colors[vd.index]); } BKE_pbvh_vertex_iter_end; @@ -1161,8 +1160,7 @@ static void sculpt_expand_restore_mask_data(SculptSession *ss, ExpandCache *expa for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { *vd.mask = expand_cache->original_mask[vd.index]; } BKE_pbvh_vertex_iter_end; @@ -1231,8 +1229,7 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata, bool any_changed = false; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { const float initial_mask = *vd.mask; const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); @@ -1304,8 +1301,7 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, bool any_changed = false; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { float initial_color[4]; copy_v4_v4(initial_color, vd.col); diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 332e551c577..17c4beab086 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -138,8 +138,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { MeshElemMap *vert_map = &ss->pmap[vd.index]; for (int j = 0; j < ss->pmap[vd.index].count; j++) { @@ -214,8 +213,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index b5fade32a25..de9511bab6f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -110,8 +110,7 @@ static void color_filter_task_cb(void *__restrict userdata, SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float orig_color[3], final_color[4], hsv_color[3]; int hue; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 0297ed73dd4..10f141e2311 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -112,8 +112,7 @@ static void mask_filter_task_cb(void *__restrict userdata, contrast = -0.1f; } - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float delta, gain, offset, max, min; float prev_val = *vd.mask; SculptVertexNeighborIter ni; @@ -363,8 +362,7 @@ static void dirty_mask_compute_range_task_cb(void *__restrict userdata, DirtyMaskRangeData *range = tls->userdata_chunk; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float dirty_mask = neighbor_dirty_mask(ss, &vd); range->min = min_ff(dirty_mask, range->min); range->max = max_ff(dirty_mask, range->max); @@ -403,8 +401,7 @@ static void dirty_mask_apply_task_cb(void *__restrict userdata, range = 1.0f / range; } - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float dirty_mask = neighbor_dirty_mask(ss, &vd); float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range)); if (dirty_only) { diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 3cf6a8cc561..3fc1a7674f7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -302,8 +302,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3]; float fade = vd.mask ? *vd.mask : 0.0f; @@ -586,8 +585,7 @@ static void mesh_filter_surface_smooth_displace_task_cb( PBVHNode *node = data->nodes[i]; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 5e229e020ad..9b06b2ee5d5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -85,8 +85,7 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op) } else { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { *vd.mask = ss->filter_cache->prev_mask[vd.index]; } BKE_pbvh_vertex_iter_end; @@ -114,8 +113,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata, PBVHVertexIter vd; int update_it = data->mask_expand_update_it; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { int vi = vd.index; float final_mask = *vd.mask; if (data->mask_expand_use_normals) { @@ -227,8 +225,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * for (int n = 0; n < ss->filter_cache->totnode; n++) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE) { const float mask = (vd.mask) ? *vd.mask : 0.0f; if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) { if (SCULPT_check_vertex_pivot_symmetry( diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c index b2fae9198fd..0c383cdf035 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -24,8 +24,8 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BLI_math.h" #include "BLI_hash.h" +#include "BLI_math.h" #include "BLI_task.h" #include "BLT_translation.h" @@ -109,8 +109,7 @@ static void mask_init_task_cb(void *__restrict userdata, const int mode = data->mask_init_mode; const int seed = data->mask_init_seed; SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { switch (mode) { case SCULPT_MASK_INIT_RANDOM_PER_VERTEX: *vd.mask = BLI_hash_int_01(vd.index + seed); diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index cfc31e1dcdd..f78f30a2cfd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -85,8 +85,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, test_radius *= brush->normal_radius_factor; test.radius_squared = test_radius * test_radius; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -166,8 +165,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index 5fdf8415f28..c3977b28178 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -85,8 +85,7 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -139,8 +138,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, BKE_brush_color_get(ss->scene, brush)); IMB_colormanagement_srgb_to_scene_linear_v3(brush_color); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); bool affect_vertex = false; @@ -227,8 +225,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata, test.radius *= data->brush->wet_paint_radius_factor; test.radius_squared = test.radius * test.radius; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -384,8 +381,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -454,8 +450,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index)); } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index a85f805894b..4d2a1bf13dc 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -174,8 +174,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float total_disp[3]; @@ -232,8 +231,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const char symm = SCULPT_mesh_symmetry_xyz_get(data->ob); PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SculptVertexNeighborIter ni; float max = 0.0f; @@ -605,8 +603,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata, SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SculptVertexNeighborIter ni; float avg = 0.0f; int total = 0; diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 4c0795eb0f7..61984610a5a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -229,8 +229,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -312,8 +311,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -473,8 +471,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -516,8 +513,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 4554ea178ab..3c0a591e8a7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -164,8 +164,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata, PBVHVertexIter vd; SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float transformed_co[3], orig_co[3], disp[3]; float *start_co; @@ -335,8 +334,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) if (mode == SCULPT_PIVOT_POSITION_UNMASKED) { for (int n = 0; n < totnode; n++) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { const float mask = (vd.mask) ? *vd.mask : 0.0f; if (mask < 1.0f) { if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) { @@ -354,8 +352,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) for (int n = 0; n < totnode; n++) { PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { const float mask = (vd.mask) ? *vd.mask : 0.0f; if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) { if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index b1e71a27dfc..4d063099216 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1104,8 +1104,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v3_v3(unode->co[vd.i], vd.co); if (vd.no) { copy_v3_v3_short(unode->no[vd.i], vd.no); @@ -1147,8 +1146,7 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { unode->mask[vd.i] = *vd.mask; } BKE_pbvh_vertex_iter_end; @@ -1159,8 +1157,7 @@ static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v4_v4(unode->col[vd.i], vd.col); } BKE_pbvh_vertex_iter_end; @@ -1258,8 +1255,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt case SCULPT_UNDO_MASK: /* Before any vertex values get modified, ensure their * original positions are logged. */ - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset); } BKE_pbvh_vertex_iter_end; @@ -1268,8 +1264,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt case SCULPT_UNDO_HIDDEN: { GSetIterator gs_iter; GSet *faces = BKE_pbvh_bmesh_node_faces(node); - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) - { + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset); } BKE_pbvh_vertex_iter_end; -- cgit v1.2.3