WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
135 changed files with 1681 additions and 971 deletions
Showing only changes of commit ee06ffdeb3 - Show all commits

View File

@ -347,10 +347,7 @@ void PathTraceWorkCPU::guiding_push_sample_data_to_global_storage(
/* Write debug render pass to validate it matches combined pass. */
pgl_vec3f pgl_final_color = kg->opgl_path_segment_storage->CalculatePixelEstimate(false);
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + render_buffer_offset;
ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer);
float3 final_color = make_float3(pgl_final_color.x, pgl_final_color.y, pgl_final_color.z);
if (kernel_data.film.pass_guiding_color != PASS_UNUSED) {
film_write_pass_float3(buffer + kernel_data.film.pass_guiding_color, final_color);

View File

@ -60,10 +60,7 @@ ccl_device_inline float bsdf_get_roughness_pass_squared(ccl_private const Shader
/* An additional term to smooth illumination on grazing angles when using bump mapping.
* Based on "Taming the Shadow Terminator" by Matt Jen-Yuan Chiang,
* Yining Karl Li and Brent Burley. */
ccl_device_inline float bump_shadowing_term(ccl_private const ShaderData &sd,
float3 Ng,
float3 N,
float3 I)
ccl_device_inline float bump_shadowing_term(int shader_flag, float3 Ng, float3 N, float3 I)
{
const float cosNI = dot(N, I);
if (cosNI < 0.0f) {
@ -82,7 +79,7 @@ ccl_device_inline float bump_shadowing_term(ccl_private const ShaderData &sd,
}
/* When bump map correction is not used do skip the smoothing. */
if ((sd.flag & SD_USE_BUMP_MAP_CORRECTION) == 0) {
if ((shader_flag & SD_USE_BUMP_MAP_CORRECTION) == 0) {
return 1.0f;
}
@ -244,7 +241,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
}
if (label & LABEL_DIFFUSE) {
if (!isequal(sc->N, sd->N)) {
*eval *= bump_shadowing_term(*sd, sd->N, sc->N, *wo);
*eval *= bump_shadowing_term(sd->flag, sd->N, sc->N, *wo);
}
}
}
@ -540,7 +537,7 @@ ccl_device_inline
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
if (!isequal(sc->N, sd->N)) {
eval *= bump_shadowing_term(*sd, sd->N, sc->N, wo);
eval *= bump_shadowing_term(sd->flag, sd->N, sc->N, wo);
}
}

View File

@ -186,7 +186,7 @@ ccl_device int bsdf_hair_chiang_setup(ccl_private ShaderData *sd, ccl_private Ch
bsdf->N = Y;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
}
#endif /* __HAIR__ */

View File

@ -101,7 +101,7 @@ ccl_device_forceinline float curve_ribbon_v(
curve[3] = kernel_data_fetch(curve_keys, kb);
}
else {
motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
motion_curve_keys(kg, object, time, ka, k0, k1, kb, curve);
}
float3 ray_P = ray->P;

View File

@ -18,10 +18,7 @@ ccl_device_forceinline bool film_need_sample_pixel(KernelGlobals kg,
return true;
}
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + render_buffer_offset;
ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer);
const uint aux_w_offset = kernel_data.film.pass_adaptive_aux_buffer + 3;
return buffer[aux_w_offset] == 0.0f;

View File

@ -466,10 +466,7 @@ ccl_device_inline void film_write_direct_light(KernelGlobals kg,
Spectrum contribution = INTEGRATOR_STATE(state, shadow_path, throughput);
film_clamp_light(kg, &contribution, INTEGRATOR_STATE(state, shadow_path, bounce));
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index);
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + render_buffer_offset;
ccl_global float *buffer = film_pass_pixel_render_buffer_shadow(kg, state, render_buffer);
const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
const int sample = INTEGRATOR_STATE(state, shadow_path, sample);

View File

@ -23,6 +23,17 @@ ccl_device_forceinline ccl_global float *film_pass_pixel_render_buffer(
return render_buffer + render_buffer_offset;
}
ccl_device_forceinline ccl_global float *film_pass_pixel_render_buffer_shadow(
KernelGlobals kg,
ConstIntegratorShadowState state,
ccl_global float *ccl_restrict render_buffer)
{
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, shadow_path, render_pixel_index);
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
kernel_data.film.pass_stride;
return render_buffer + render_buffer_offset;
}
/* Accumulate in passes. */
ccl_device_inline void film_write_pass_float(ccl_global float *ccl_restrict buffer, float value)

View File

@ -207,7 +207,7 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData
P_curve[1] = kernel_data_fetch(curve_keys, k1);
}
else {
motion_curve_keys_linear(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
motion_curve_keys_linear(kg, sd->object, sd->time, k0, k1, P_curve);
}
r = (P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w;

View File

@ -650,7 +650,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
curve[3] = kernel_data_fetch(curve_keys, kb);
}
else {
motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
motion_curve_keys(kg, object, time, ka, k0, k1, kb, curve);
}
if (type & PRIMITIVE_CURVE_RIBBON) {
@ -682,7 +682,6 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
float3 P,
float3 D,
float t,
const int isect_object,
const int isect_prim)
{
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
@ -709,7 +708,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
P_curve[3] = kernel_data_fetch(curve_keys, kb);
}
else {
motion_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve);
motion_curve_keys(kg, sd->object, sd->time, ka, k0, k1, kb, P_curve);
}
P = P + D * t;

View File

@ -45,7 +45,7 @@ ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg,
/* return 2 curve key locations */
ccl_device_inline void motion_curve_keys_linear(
KernelGlobals kg, int object, int prim, float time, int k0, int k1, float4 keys[2])
KernelGlobals kg, int object, float time, int k0, int k1, float4 keys[2])
{
/* get motion info */
const int numsteps = kernel_data_fetch(objects, object).numsteps;
@ -104,15 +104,8 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
}
/* return 2 curve key locations */
ccl_device_inline void motion_curve_keys(KernelGlobals kg,
int object,
int prim,
float time,
int k0,
int k1,
int k2,
int k3,
float4 keys[4])
ccl_device_inline void motion_curve_keys(
KernelGlobals kg, int object, float time, int k0, int k1, int k2, int k3, float4 keys[4])
{
/* get motion info */
const int numsteps = kernel_data_fetch(objects, object).numsteps;

View File

@ -20,13 +20,8 @@ CCL_NAMESPACE_BEGIN
/**
* Use the barycentric coordinates to get the intersection location
*/
ccl_device_inline float3 motion_triangle_point_from_uv(KernelGlobals kg,
ccl_private ShaderData *sd,
const int isect_object,
const int isect_prim,
const float u,
const float v,
float3 verts[3])
ccl_device_inline float3 motion_triangle_point_from_uv(
KernelGlobals kg, ccl_private ShaderData *sd, const float u, const float v, float3 verts[3])
{
/* This appears to give slightly better precision than interpolating with w = (1 - u - v). */
float3 P = verts[0] + u * (verts[1] - verts[0]) + v * (verts[2] - verts[0]);

View File

@ -22,14 +22,7 @@ CCL_NAMESPACE_BEGIN
* normals */
/* return 3 triangle vertex normals */
ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
const float3 P,
const float3 D,
const float ray_t,
const int isect_object,
const int isect_prim,
bool is_local)
ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg, ccl_private ShaderData *sd)
{
/* Get shader. */
sd->shader = kernel_data_fetch(tri_shader, sd->prim);
@ -46,7 +39,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
motion_triangle_vertices(kg, sd->object, tri_vindex, numsteps, numverts, step, t, verts);
/* Compute refined position. */
sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
sd->P = motion_triangle_point_from_uv(kg, sd, sd->u, sd->v, verts);
/* Compute face normal. */
float3 Ng;
if (object_negative_scale_applied(sd->object_flag)) {

View File

@ -61,7 +61,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
#ifdef __HAIR__
if (sd->type & PRIMITIVE_CURVE) {
/* curve */
curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->prim);
}
else
#endif
@ -76,27 +76,11 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
{
if (sd->type == PRIMITIVE_TRIANGLE) {
/* static triangle */
float3 Ng = triangle_normal(kg, sd);
sd->shader = kernel_data_fetch(tri_shader, sd->prim);
/* vectors */
sd->P = triangle_point_from_uv(kg, sd, isect->object, isect->prim, isect->u, isect->v);
sd->Ng = Ng;
sd->N = Ng;
/* smooth normal */
if (sd->shader & SHADER_SMOOTH_NORMAL)
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
#ifdef __DPDU__
/* dPdu/dPdv */
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
#endif
triangle_shader_setup(kg, sd);
}
else {
/* motion triangle */
motion_triangle_shader_setup(
kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
motion_triangle_shader_setup(kg, sd);
}
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {

View File

@ -139,7 +139,6 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
*/
ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
ccl_private ShaderData *sd,
const int isect_object,
const int isect_prim,
const float u,
const float v)
@ -160,4 +159,26 @@ ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
return P;
}
ccl_device_inline void triangle_shader_setup(KernelGlobals kg, ccl_private ShaderData *sd)
{
sd->shader = kernel_data_fetch(tri_shader, sd->prim);
sd->P = triangle_point_from_uv(kg, sd, sd->prim, sd->u, sd->v);
/* Normals. */
float3 Ng = triangle_normal(kg, sd);
sd->Ng = Ng;
sd->N = Ng;
/* Smooth normal. */
if (sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
}
#ifdef __DPDU__
/* dPdu/dPdv */
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
#endif
}
CCL_NAMESPACE_END

View File

@ -472,10 +472,7 @@ ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
return;
}
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + render_buffer_offset;
ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer);
if (kernel_data.film.pass_guiding_probability != PASS_UNUSED) {
float guiding_prob = state->guiding.surface_guiding_sampling_prob;

View File

@ -125,9 +125,7 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
kg, state, render_buffer, scheduled_sample, tile->sample_offset);
/* Setup render buffers. */
const int index = INTEGRATOR_STATE(state, path, render_pixel_index);
const int pass_stride = kernel_data.film.pass_stride;
ccl_global float *buffer = render_buffer + (uint64_t)index * pass_stride;
ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer);
ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive;
ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential;

View File

@ -150,7 +150,7 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state)
{
/* Verify that the kernel is only scheduled if it is actually needed. */
kernel_assert(shadow_linking_scene_need_shadow_ray(kg, state));
kernel_assert(shadow_linking_scene_need_shadow_ray(kg));
/* Read ray from integrator state into local memory. */
Ray ray ccl_optional_struct_init;

View File

@ -157,8 +157,7 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
kg, sd_vtx->object, sd_vtx->prim, sd_vtx->time, verts, normals);
/* Compute refined position. */
sd_vtx->P = motion_triangle_point_from_uv(
kg, sd_vtx, isect->object, isect->prim, isect->u, isect->v, verts);
sd_vtx->P = motion_triangle_point_from_uv(kg, sd_vtx, isect->u, isect->v, verts);
}
/* Instance transform. */

View File

@ -107,13 +107,7 @@ ccl_device_inline void integrate_background(KernelGlobals kg,
}
/* Background MIS weights. */
float mis_weight = 1.0f;
/* Check if background light exists or if we should skip PDF. */
if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) &&
kernel_data.background.use_mis)
{
mis_weight = light_sample_mis_weight_forward_background(kg, state, path_flag);
}
const float mis_weight = light_sample_mis_weight_forward_background(kg, state, path_flag);
guiding_record_background(kg, state, L, mis_weight);
L *= mis_weight;
@ -174,10 +168,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
}
/* MIS weighting. */
float mis_weight = 1.0f;
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = light_sample_mis_weight_forward_distant(kg, state, path_flag, &ls);
}
const float mis_weight = light_sample_mis_weight_forward_distant(kg, state, path_flag, &ls);
/* Write to render buffer. */
guiding_record_background(kg, state, light_eval, mis_weight);

View File

@ -110,24 +110,17 @@ ccl_device bool shadow_linking_shade_light(KernelGlobals kg,
}
/* MIS weighting. */
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
}
mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
bsdf_spectrum = light_eval * mis_weight *
INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
// TODO(: De-duplicate with the shade_surface.
// Possibly by ensuring ls->group is always assigned properly.
light_group = ls.type != LIGHT_BACKGROUND ? ls.group : kernel_data.background.lightgroup;
light_group = ls.group;
return true;
}
ccl_device bool shadow_linking_shade_surface_emission(KernelGlobals kg,
IntegratorState state,
ccl_private Ray &ccl_restrict ray,
ccl_private Intersection &ccl_restrict isect,
ccl_private ShaderData *emission_sd,
ccl_global float *ccl_restrict render_buffer,
ccl_private Spectrum &ccl_restrict
@ -154,18 +147,7 @@ ccl_device bool shadow_linking_shade_surface_emission(KernelGlobals kg,
const Spectrum L = surface_shader_emission(emission_sd);
const bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(emission_sd->flag &
((emission_sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
# ifdef __HAIR__
if (has_mis && (emission_sd->type & PRIMITIVE_TRIANGLE))
# else
if (has_mis)
# endif
{
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, emission_sd);
}
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, emission_sd);
bsdf_spectrum = L * mis_weight * INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
light_group = object_lightgroup(kg, emission_sd->object);
@ -200,15 +182,8 @@ ccl_device void shadow_linking_shade(KernelGlobals kg,
}
}
else {
if (!shadow_linking_shade_surface_emission(kg,
state,
ray,
isect,
emission_sd,
render_buffer,
bsdf_spectrum,
mis_weight,
light_group))
if (!shadow_linking_shade_surface_emission(
kg, state, emission_sd, render_buffer, bsdf_spectrum, mis_weight, light_group))
{
return;
}

View File

@ -55,10 +55,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
}
/* MIS weighting. */
float mis_weight = 1.0f;
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray_P);
}
const float mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray_P);
/* Write to render buffer. */
guiding_record_surface_emission(kg, state, light_eval, mis_weight);

View File

@ -138,19 +138,8 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
/* Evaluate emissive closure. */
Spectrum L = surface_shader_emission(sd);
float mis_weight = 1.0f;
const bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(sd->flag & ((sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
#ifdef __HAIR__
if (has_mis && (sd->type & PRIMITIVE_TRIANGLE))
#else
if (has_mis)
#endif
{
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, sd);
}
const float mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, sd);
guiding_record_surface_emission(kg, state, L, mis_weight);
film_write_surface_emission(
@ -263,7 +252,6 @@ ccl_device
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
if (!light_sample_from_position(kg,
rng_state,
rand_light,
sd->time,
sd->P,
@ -339,16 +327,12 @@ ccl_device
/* Evaluate BSDF. */
const float bsdf_pdf = surface_shader_bsdf_eval(kg, state, sd, ls.D, &bsdf_eval, ls.shader);
bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf);
if (ls.shader & SHADER_USE_MIS) {
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf);
bsdf_eval_mul(&bsdf_eval, mis_weight);
}
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf);
bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf * mis_weight);
/* Path termination. */
const float terminate = path_state_rng_light_termination(kg, rng_state);
if (light_sample_terminate(kg, &ls, &bsdf_eval, terminate)) {
if (light_sample_terminate(kg, &bsdf_eval, terminate)) {
return;
}
@ -361,13 +345,8 @@ ccl_device
}
/* Branch off shadow kernel. */
// TODO(: De-duplicate with the shade_Dedicated_light.
// Possibly by ensuring ls->group is always assigned properly.
const int light_group = ls.type != LIGHT_BACKGROUND ? ls.group :
kernel_data.background.lightgroup;
IntegratorShadowState shadow_state = integrate_direct_light_shadow_init_common(
kg, state, &ray, bsdf_eval_sum(&bsdf_eval), light_group, mnee_vertex_count);
kg, state, &ray, bsdf_eval_sum(&bsdf_eval), ls.group, mnee_vertex_count);
if (is_transmission) {
#ifdef __VOLUME__
@ -570,8 +549,7 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
IntegratorState state,
ccl_private const ShaderData *ccl_restrict sd,
ccl_private const RNGState *ccl_restrict
rng_state,
ccl_global float *ccl_restrict render_buffer)
rng_state)
{
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
@ -752,7 +730,7 @@ ccl_device int integrate_surface(KernelGlobals kg,
/* Ambient occlusion pass. */
if (kernel_data.kernel_features & KERNEL_FEATURE_AO) {
PROFILING_EVENT(PROFILING_SHADE_SURFACE_AO);
integrate_surface_ao(kg, state, &sd, &rng_state, render_buffer);
integrate_surface_ao(kg, state, &sd, &rng_state);
}
#endif

View File

@ -798,18 +798,13 @@ ccl_device_forceinline void integrate_volume_direct_light(
/* Evaluate BSDF. */
BsdfEval phase_eval ccl_optional_struct_init;
float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls.D, &phase_eval);
if (ls.shader & SHADER_USE_MIS) {
float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf);
bsdf_eval_mul(&phase_eval, mis_weight);
}
bsdf_eval_mul(&phase_eval, light_eval / ls.pdf);
float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls.D, &phase_eval, ls.shader);
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf);
bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
/* Path termination. */
const float terminate = path_state_rng_light_termination(kg, rng_state);
if (light_sample_terminate(kg, &ls, &phase_eval, terminate)) {
if (light_sample_terminate(kg, &phase_eval, terminate)) {
return;
}
@ -871,10 +866,7 @@ ccl_device_forceinline void integrate_volume_direct_light(
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase;
/* Write Light-group, +1 as light-group is int but we need to encode into a uint8_t. */
INTEGRATOR_STATE_WRITE(
shadow_state, shadow_path, lightgroup) = (ls.type != LIGHT_BACKGROUND) ?
ls.group + 1 :
kernel_data.background.lightgroup + 1;
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, lightgroup) = ls.group + 1;
# ifdef __PATH_GUIDING__
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput;

View File

@ -13,8 +13,7 @@ CCL_NAMESPACE_BEGIN
/* Check whether special shadow rays for shadow linking are needed in the current scene
* configuration. */
ccl_device_forceinline bool shadow_linking_scene_need_shadow_ray(KernelGlobals kg,
IntegratorState state)
ccl_device_forceinline bool shadow_linking_scene_need_shadow_ray(KernelGlobals kg)
{
if (!(kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING)) {
/* No shadow linking in the scene, so no need to trace any extra rays. */
@ -57,7 +56,7 @@ template<DeviceKernel current_kernel>
ccl_device_inline bool shadow_linking_schedule_intersection_kernel(KernelGlobals kg,
IntegratorState state)
{
if (!shadow_linking_scene_need_shadow_ray(kg, state)) {
if (!shadow_linking_scene_need_shadow_ray(kg)) {
return false;
}

View File

@ -364,6 +364,12 @@ ccl_device_inline
float pdf = _surface_shader_bsdf_eval_mis(
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
/* If the light does not use MIS, then it is only sampled via NEE, so the probability of hitting
* the light using BSDF sampling is zero. */
if (!(light_shader_flags & SHADER_USE_MIS)) {
pdf = 0.0f;
}
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
if (pdf > 0.0f && state->guiding.use_surface_guiding) {
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;

View File

@ -249,7 +249,8 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderVolumePhases *phases,
const float3 wo,
ccl_private BsdfEval *phase_eval)
ccl_private BsdfEval *phase_eval,
const uint light_shader_flags)
{
bsdf_eval_init(phase_eval, zero_spectrum());
@ -263,6 +264,12 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
}
# endif
/* If the light does not use MIS, then it is only sampled via NEE, so the probability of hitting
* the light using BSDF sampling is zero. */
if (!(light_shader_flags & SHADER_USE_MIS)) {
pdf = 0.0f;
}
return pdf;
}

View File

@ -473,12 +473,12 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
ls->group = lamp_lightgroup(kg, lamp);
if (type == LIGHT_SPOT) {
if (!spot_light_sample_from_intersection(klight, isect, ray_P, ray_D, N, path_flag, ls)) {
if (!spot_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) {
return false;
}
}
else if (type == LIGHT_POINT) {
if (!point_light_sample_from_intersection(klight, isect, ray_P, ray_D, N, path_flag, ls)) {
if (!point_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) {
return false;
}
}

View File

@ -148,14 +148,13 @@ ccl_device_inline bool point_light_intersect(const ccl_global KernelLight *kligh
}
}
ccl_device_inline bool point_light_sample_from_intersection(
const ccl_global KernelLight *klight,
ccl_private const Intersection *ccl_restrict isect,
const float3 ray_P,
const float3 ray_D,
const float3 N,
const uint32_t path_flag,
ccl_private LightSample *ccl_restrict ls)
ccl_device_inline bool point_light_sample_from_intersection(const ccl_global KernelLight *klight,
const float3 ray_P,
const float3 ray_D,
const float3 N,
const uint32_t path_flag,
ccl_private LightSample *ccl_restrict
ls)
{
const float r_sq = sqr(klight->spot.radius);

View File

@ -91,7 +91,6 @@ light_sample_shader_eval(KernelGlobals kg,
/* Early path termination of shadow rays. */
ccl_device_inline bool light_sample_terminate(KernelGlobals kg,
ccl_private const LightSample *ccl_restrict ls,
ccl_private BsdfEval *ccl_restrict eval,
const float rand_terminate)
{
@ -301,7 +300,10 @@ ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg,
{
#ifdef WITH_CYCLES_DEBUG
if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) {
return 0.0f;
/* Return 0.0f to only account for the contribution in forward path tracing, unless when the
* light can not be forward sampled, in which case return 1.0f so it converges to the same
* result. */
return (forward_pdf == 0.0f);
}
else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) {
return 1.0f;
@ -351,7 +353,6 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
}
ccl_device bool light_sample_from_position(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const float3 rand,
const float time,
const float3 P,
@ -422,6 +423,17 @@ ccl_device_inline float light_sample_mis_weight_forward_surface(KernelGlobals kg
const uint32_t path_flag,
const ccl_private ShaderData *sd)
{
bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(sd->flag & ((sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
#ifdef __HAIR__
has_mis &= (sd->type & PRIMITIVE_TRIANGLE);
#endif
if (!has_mis) {
return 1.0f;
}
const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
const float t = sd->ray_length;
float pdf = triangle_light_pdf(kg, sd, t);
@ -455,6 +467,10 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg,
const ccl_private LightSample *ls,
const float3 P)
{
if (path_flag & PATH_RAY_MIS_SKIP) {
return 1.0f;
}
const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
float pdf = ls->pdf;
@ -494,6 +510,11 @@ ccl_device_inline float light_sample_mis_weight_forward_background(KernelGlobals
IntegratorState state,
const uint32_t path_flag)
{
/* Check if background light exists or if we should skip PDF. */
if (!kernel_data.background.use_mis || (path_flag & PATH_RAY_MIS_SKIP)) {
return 1.0f;
}
const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);

View File

@ -220,14 +220,13 @@ ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight
return point_light_intersect(klight, ray, t);
}
ccl_device_inline bool spot_light_sample_from_intersection(
const ccl_global KernelLight *klight,
ccl_private const Intersection *ccl_restrict isect,
const float3 ray_P,
const float3 ray_D,
const float3 N,
const uint32_t path_flag,
ccl_private LightSample *ccl_restrict ls)
ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global KernelLight *klight,
const float3 ray_P,
const float3 ray_D,
const float3 N,
const uint32_t path_flag,
ccl_private LightSample *ccl_restrict
ls)
{
const float r_sq = sqr(klight->spot.radius);
const float d_sq = len_squared(ray_P - klight->co);

View File

@ -134,7 +134,6 @@ ccl_device void light_tree_importance(const float3 N_or_D,
const BoundingCone bcone,
const float max_distance,
const float min_distance,
const float t,
const float energy,
ccl_private float &max_importance,
ccl_private float &min_importance)
@ -370,7 +369,6 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
bcone,
distance,
distance,
t,
knode->energy,
max_importance,
min_importance);
@ -477,7 +475,6 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
bcone,
distance.x,
distance.y,
t,
kemitter->energy,
max_importance,
min_importance);

View File

@ -203,24 +203,14 @@ ccl_device float3 svm_bevel(
/* Quickly retrieve P and Ng without setting up ShaderData. */
float3 hit_P;
if (sd->type == PRIMITIVE_TRIANGLE) {
hit_P = triangle_point_from_uv(kg,
sd,
isect.hits[hit].object,
isect.hits[hit].prim,
isect.hits[hit].u,
isect.hits[hit].v);
hit_P = triangle_point_from_uv(
kg, sd, isect.hits[hit].prim, isect.hits[hit].u, isect.hits[hit].v);
}
# ifdef __OBJECT_MOTION__
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
float3 verts[3];
motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
hit_P = motion_triangle_point_from_uv(kg,
sd,
isect.hits[hit].object,
isect.hits[hit].prim,
isect.hits[hit].u,
isect.hits[hit].v,
verts);
hit_P = motion_triangle_point_from_uv(kg, sd, isect.hits[hit].u, isect.hits[hit].v, verts);
}
# endif /* __OBJECT_MOTION__ */

View File

@ -1376,12 +1376,18 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
klights[light_index].tfm = light->tfm;
klights[light_index].itfm = transform_inverse(light->tfm);
auto it = scene->lightgroups.find(light->lightgroup);
if (it != scene->lightgroups.end()) {
klights[light_index].lightgroup = it->second;
/* Light group. */
if (light->light_type == LIGHT_BACKGROUND) {
klights[light_index].lightgroup = dscene->data.background.lightgroup;
}
else {
klights[light_index].lightgroup = LIGHTGROUP_NONE;
auto it = scene->lightgroups.find(light->lightgroup);
if (it != scene->lightgroups.end()) {
klights[light_index].lightgroup = it->second;
}
else {
klights[light_index].lightgroup = LIGHTGROUP_NONE;
}
}
klights[light_index].light_set_membership = light->light_set_membership;

View File

@ -37,7 +37,6 @@ if(WITH_OPENSUBDIV)
# Base.
internal/base/memory.h
internal/base/opensubdiv_capi.cc
internal/base/type.h
internal/base/type_convert.cc
internal/base/type_convert.h
internal/base/util.cc

View File

@ -1,39 +0,0 @@
/* SPDX-FileCopyrightText: 2013 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENSUBDIV_BASE_TYPE_H_
#define OPENSUBDIV_BASE_TYPE_H_
#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <map>
#include <stack>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace blender {
namespace opensubdiv {
using std::map;
using std::pair;
using std::stack;
using std::string;
using std::unordered_map;
using std::vector;
using std::fill;
using std::make_pair;
using std::max;
using std::min;
using std::move;
using std::swap;
} // namespace opensubdiv
} // namespace blender
#endif // OPENSUBDIV_BASE_TYPE_H_

View File

@ -7,22 +7,22 @@
namespace blender {
namespace opensubdiv {
void stringSplit(vector<string> *tokens,
const string &str,
const string &separators,
void stringSplit(std::vector<std::string> *tokens,
const std::string &str,
const std::string &separators,
bool skip_empty)
{
size_t token_start = 0, token_length = 0;
for (size_t i = 0; i < str.length(); ++i) {
const char ch = str[i];
if (separators.find(ch) == string::npos) {
if (separators.find(ch) == std::string::npos) {
// Append non-separator char to a token.
++token_length;
}
else {
// Append current token to the list (if any).
if (token_length > 0 || !skip_empty) {
string token = str.substr(token_start, token_length);
std::string token = str.substr(token_start, token_length);
tokens->push_back(token);
}
// Re-set token pointers.
@ -30,11 +30,11 @@ void stringSplit(vector<string> *tokens,
token_length = 0;
}
}
// Append token which might be at the end of the string.
if ((token_length != 0) ||
(!skip_empty && token_start > 0 && separators.find(str[token_start - 1]) != string::npos))
// Append token which might be at the end of the std::string.
if ((token_length != 0) || (!skip_empty && token_start > 0 &&
separators.find(str[token_start - 1]) != std::string::npos))
{
string token = str.substr(token_start, token_length);
std::string token = str.substr(token_start, token_length);
tokens->push_back(token);
}
}

View File

@ -5,14 +5,15 @@
#ifndef OPENSUBDIV_BASE_UTIL_H_
#define OPENSUBDIV_BASE_UTIL_H_
#include "internal/base/type.h"
#include <string>
#include <vector>
namespace blender {
namespace opensubdiv {
void stringSplit(vector<string> *tokens,
const string &str,
const string &separators,
void stringSplit(std::vector<std::string> *tokens,
const std::string &str,
const std::string &separators,
bool skip_empty);
} // namespace opensubdiv

View File

@ -12,7 +12,6 @@
#include <opensubdiv/osd/mesh.h>
#include <opensubdiv/osd/types.h>
#include "internal/base/type.h"
#include "internal/evaluator/evaluator_impl.h"
#include "opensubdiv_evaluator_capi.hh"
@ -325,7 +324,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
VolatileEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const std::vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL,
@ -641,7 +640,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
const STENCIL_TABLE *varying_stencils_;
int face_varying_width_;
vector<FaceVaryingEval *> face_varying_evaluators_;
std::vector<FaceVaryingEval *> face_varying_evaluators_;
EvaluatorCache *evaluator_cache_;
DEVICE_CONTEXT *device_context_;

View File

@ -30,7 +30,7 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
public:
CpuEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const std::vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL)

View File

@ -31,7 +31,7 @@ static void buildPatchArraysBufferFromVector(const PatchArrayVector &patch_array
GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const std::vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const PatchTable *patch_table,
VolatileEvalOutput::EvaluatorCache *evaluator_cache)

View File

@ -26,7 +26,7 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
public:
GpuEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const std::vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL);

View File

@ -22,7 +22,6 @@
#include "MEM_guardedalloc.h"
#include "internal/base/type.h"
#include "internal/evaluator/eval_output_cpu.h"
#include "internal/evaluator/eval_output_gpu.h"
#include "internal/evaluator/evaluator_cache_impl.h"
@ -90,7 +89,8 @@ template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
T *old_buffer = effective_elements_;
effective_elements_ = allocate(num_elements);
if (old_buffer != effective_elements_) {
memcpy(effective_elements_, old_buffer, sizeof(T) * min(old_num_elements, num_elements));
memcpy(
effective_elements_, old_buffer, sizeof(T) * std::min(old_num_elements, num_elements));
}
if (old_buffer != stack_elements_) {
delete[] old_buffer;
@ -430,7 +430,6 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
{
using blender::opensubdiv::vector;
TopologyRefiner *refiner = topology_refiner->impl->topology_refiner;
if (refiner == NULL) {
// Happens on bad topology.
@ -480,7 +479,7 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options);
}
// Face warying stencil.
vector<const StencilTable *> all_face_varying_stencils;
std::vector<const StencilTable *> all_face_varying_stencils;
all_face_varying_stencils.reserve(num_face_varying_channels);
for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
++face_varying_channel)

View File

@ -222,8 +222,8 @@ bool MeshTopology::isFaceVertexIndicesEqual(int face_index,
sizeof(int) * num_expected_face_vertex_indices) == 0;
}
bool MeshTopology::isFaceVertexIndicesEqual(int face_index,
const vector<int> &expected_face_vertex_indices) const
bool MeshTopology::isFaceVertexIndicesEqual(
int face_index, const std::vector<int> &expected_face_vertex_indices) const
{
return isFaceVertexIndicesEqual(
face_index, expected_face_vertex_indices.size(), expected_face_vertex_indices.data());

View File

@ -7,10 +7,9 @@
#ifndef OPENSUBDIV_MESH_TOPOLOGY_H_
#define OPENSUBDIV_MESH_TOPOLOGY_H_
#include <cstring>
#include <vector>
#include "internal/base/memory.h"
#include "internal/base/type.h"
struct OpenSubdiv_Converter;
@ -93,7 +92,7 @@ class MeshTopology {
int num_expected_face_vertex_indices,
const int *expected_face_vertex_indices) const;
bool isFaceVertexIndicesEqual(int face_index,
const vector<int> &expected_face_vertex_indices) const;
const std::vector<int> &expected_face_vertex_indices) const;
//////////////////////////////////////////////////////////////////////////////
// Pipeline related.
@ -142,21 +141,21 @@ class MeshTopology {
};
int num_vertices_;
vector<VertexTag> vertex_tags_;
std::vector<VertexTag> vertex_tags_;
int num_edges_;
vector<Edge> edges_;
vector<EdgeTag> edge_tags_;
std::vector<Edge> edges_;
std::vector<EdgeTag> edge_tags_;
int num_faces_;
// Continuous array of all vertices of all faces:
// [vertex indices of face 0][vertex indices of face 1] .. [vertex indices of face n].
vector<int> face_vertex_indices_;
std::vector<int> face_vertex_indices_;
// Indexed by face contains index within face_vertex_indices_ which corresponds
// to the element which contains first vertex of the face.
vector<int> faces_first_vertex_index_;
std::vector<int> faces_first_vertex_index_;
MEM_CXX_CLASS_ALLOC_FUNCS("MeshTopology");
};

View File

@ -9,8 +9,7 @@
#include <cassert>
#include <cstring>
#include <opensubdiv/sdc/crease.h>
#include "internal/base/type.h"
#include <vector>
#include "opensubdiv_converter_capi.hh"
@ -80,7 +79,7 @@ bool isEqualGeometryFace(const MeshTopology &mesh_topology, const OpenSubdiv_Con
return false;
}
vector<int> vertices_of_face;
std::vector<int> vertices_of_face;
for (int face_index = 0; face_index < num_requested_faces; ++face_index) {
int num_face_vertices = converter->getNumFaceVertices(converter, face_index);
if (mesh_topology.getNumFaceVertices(face_index) != num_face_vertices) {

View File

@ -10,8 +10,6 @@
#include "internal/base/type_convert.h"
#include "internal/topology/topology_refiner_impl.h"
using blender::opensubdiv::vector;
namespace {
const OpenSubdiv::Far::TopologyRefiner *getOSDTopologyRefiner(

View File

@ -15,16 +15,11 @@
#include <opensubdiv/far/topologyRefinerFactory.h>
#include "internal/base/type.h"
#include "internal/base/type_convert.h"
#include "internal/topology/mesh_topology.h"
#include "opensubdiv_converter_capi.hh"
using blender::opensubdiv::min;
using blender::opensubdiv::stack;
using blender::opensubdiv::vector;
struct TopologyRefinerData {
const OpenSubdiv_Converter *converter;
blender::opensubdiv::MeshTopology *base_mesh_topology;
@ -138,7 +133,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology
// Vertex relations.
const int num_vertices = converter->getNumVertices(converter);
vector<int> vertex_faces, vertex_edges;
std::vector<int> vertex_faces, vertex_edges;
for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
// Vertex-faces.
IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index);
@ -247,8 +242,8 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
const float sharpness0 = refiner._levels[0]->getEdgeSharpness(edge0);
const float sharpness1 = refiner._levels[0]->getEdgeSharpness(edge1);
// TODO(sergey): Find a better mixing between edge and vertex sharpness.
sharpness += min(sharpness0, sharpness1);
sharpness = min(sharpness, 10.0f);
sharpness += std::min(sharpness0, sharpness1);
sharpness = std::min(sharpness, 10.0f);
}
setBaseVertexSharpness(refiner, vertex_index, sharpness);

View File

@ -6,7 +6,6 @@
#include "internal/topology/topology_refiner_impl.h"
#include "internal/base/type.h"
#include "internal/base/type_convert.h"
#include "internal/topology/mesh_topology.h"
#include "internal/topology/topology_refiner_impl.h"

View File

@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2017-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -0,0 +1,573 @@
# SPDX-FileCopyrightText: 2017-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
# TODO: file-type icons are currently not setup.
# Currently `xdg-icon-resource` doesn't support SVG's, so we would need to generate PNG's.
# Or wait until SVG's are supported, see: https://gitlab.freedesktop.org/xdg/xdg-utils/-/merge_requests/41
#
# NOTE: Typically this will run from Blender, you may also run this directly from Python
# which can be useful for testing.
__all__ = (
"register",
"unregister",
)
import argparse
import os
import shlex
import shutil
import subprocess
import sys
import tempfile
from typing import (
Callable,
Optional,
)
VERBOSE = True
# -----------------------------------------------------------------------------
# Environment
HOME_DIR = os.path.normpath(os.path.expanduser("~"))
# https://wiki.archlinux.org/title/XDG_Base_Directory
# Typically: `~/.local/share`.
XDG_DATA_HOME = os.environ.get("XDG_DATA_HOME") or os.path.join(HOME_DIR, ".local", "share")
HOMEDIR_LOCAL_BIN = os.path.join(HOME_DIR, ".local", "bin")
BLENDER_ENV = "bpy" in sys.modules
# -----------------------------------------------------------------------------
# Programs
# The command `xdg-mime` handles most of the file assosiation actions.
XDG_MIME_PROG = shutil.which("xdg-mime") or ""
# Initialize by `bpy` or command line arguments.
BLENDER_BIN = ""
# Set to `os.path.dirname(BLENDER_BIN)`.
BLENDER_DIR = ""
# -----------------------------------------------------------------------------
# Path Constants
# These files are included along side a portable Blender installation.
BLENDER_DESKTOP = "blender.desktop"
# The target binary.
BLENDER_FILENAME = "blender"
# The target binary (thumbnailer).
BLENDER_THUMBNAILER_FILENAME = "blender-thumbnailer"
# -----------------------------------------------------------------------------
# Other Constants
# The mime type Blender users.
BLENDER_MIME = "application/x-blender"
# Use `/usr/local` because this is not managed by the systems package manager.
SYSTEM_PREFIX = "/usr/local"
# -----------------------------------------------------------------------------
# Utility Functions
# Display a short path, for nicer display only.
def filepath_repr(filepath: str) -> str:
if filepath.startswith(HOME_DIR):
return "~" + filepath[len(HOME_DIR):]
return filepath
def system_path_contains(dirpath: str) -> bool:
dirpath = os.path.normpath(dirpath)
for path in os.environ.get("PATH", "").split(os.pathsep):
# `$PATH` can include relative locations.
path = os.path.normpath(os.path.abspath(path))
if path == dirpath:
return True
return False
# When removing files to make way for newly copied file an `os.path.exists`
# check isn't sufficient as the path may be a broken symbolic-link.
def path_exists_or_is_link(path: str) -> bool:
return os.path.exists(path) or os.path.islink(path)
def filepath_ensure_removed(path: str) -> bool:
if path_exists_or_is_link(path):
os.remove(path)
return True
return False
# -----------------------------------------------------------------------------
# Handle Associations
#
# On registration when handlers return False this causes registration to fail and unregister to be called.
# Non fatal errors should print a message and return True instead.
def handle_bin(do_register: bool, all_users: bool) -> Optional[str]:
if all_users:
dirpath_dst = os.path.join(SYSTEM_PREFIX, "bin")
else:
dirpath_dst = HOMEDIR_LOCAL_BIN
if VERBOSE:
sys.stdout.write("- {:s} symbolic-links in: {:s}\n".format(
("Setup" if do_register else "Remove"),
filepath_repr(dirpath_dst),
))
if do_register:
if not all_users:
if not system_path_contains(dirpath_dst):
sys.stdout.write(
"The PATH environment variable doesn't contain \"{:s}\", not creating symlinks\n".format(
dirpath_dst,
))
# NOTE: this is not an error, don't consider it a failure.
return None
os.makedirs(dirpath_dst, exist_ok=True)
# Full path, then name to create at the destination.
files_to_link = [
(BLENDER_BIN, BLENDER_FILENAME, False),
]
blender_thumbnailer_src = os.path.join(BLENDER_DIR, BLENDER_THUMBNAILER_FILENAME)
if os.path.exists(blender_thumbnailer_src):
# Unfortunately the thumbnailer must be copied for `bwrap` to find it.
files_to_link.append((blender_thumbnailer_src, BLENDER_THUMBNAILER_FILENAME, True))
else:
sys.stdout.write(" Thumbnailer not found, skipping: \"{:s}\"\n".format(blender_thumbnailer_src))
for filepath_src, filename, do_full_copy in files_to_link:
filepath_dst = os.path.join(dirpath_dst, filename)
filepath_ensure_removed(filepath_dst)
if not do_register:
continue
if not os.path.exists(filepath_src):
sys.stderr.write("File not found, skipping link: \"{:s}\" -> \"{:s}\"\n".format(
filepath_src, filepath_dst,
))
if do_full_copy:
shutil.copyfile(filepath_src, filepath_dst)
os.chmod(filepath_dst, 0o755)
else:
os.symlink(filepath_src, filepath_dst)
return None
def handle_desktop_file(do_register: bool, all_users: bool) -> Optional[str]:
# `cp ./blender.desktop ~/.local/share/applications/`
filename = BLENDER_DESKTOP
if all_users:
base_dir = os.path.join(SYSTEM_PREFIX, "share")
else:
base_dir = XDG_DATA_HOME
dirpath_dst = os.path.join(base_dir, "applications")
filepath_desktop_src = os.path.join(BLENDER_DIR, filename)
filepath_desktop_dst = os.path.join(dirpath_dst, filename)
if VERBOSE:
sys.stdout.write("- {:s} desktop-file: {:s}\n".format(
("Setup" if do_register else "Remove"),
filepath_repr(filepath_desktop_dst),
))
filepath_ensure_removed(filepath_desktop_dst)
if not do_register:
return None
if not os.path.exists(filepath_desktop_src):
# Unlike other missing things, this must be an error otherwise
# the MIME association fails which is the main purpose of registering types.
return "Error: desktop file not found: {:s}".format(filepath_desktop_src)
os.makedirs(dirpath_dst, exist_ok=True)
with open(filepath_desktop_src, "r", encoding="utf-8") as fh:
data = fh.read()
data = data.replace("\nExec=blender %f\n", "\nExec={:s} %f\n".format(BLENDER_BIN))
with open(filepath_desktop_dst, "w", encoding="utf-8") as fh:
fh.write(data)
return None
def handle_thumbnailer(do_register: bool, all_users: bool) -> Optional[str]:
filename = "blender.thumbnailer"
if all_users:
base_dir = os.path.join(SYSTEM_PREFIX, "share")
else:
base_dir = XDG_DATA_HOME
dirpath_dst = os.path.join(base_dir, "thumbnailers")
filepath_thumbnailer_dst = os.path.join(dirpath_dst, filename)
if VERBOSE:
sys.stdout.write("- {:s} thumbnailer: {:s}\n".format(
("Setup" if do_register else "Remove"),
filepath_repr(filepath_thumbnailer_dst),
))
filepath_ensure_removed(filepath_thumbnailer_dst)
if not do_register:
return None
blender_thumbnailer_bin = os.path.join(BLENDER_DIR, BLENDER_THUMBNAILER_FILENAME)
if not os.path.exists(blender_thumbnailer_bin):
sys.stderr.write("Thumbnailer not found, this may not be a portable installation: {:s}\n".format(
blender_thumbnailer_bin,
))
return None
os.makedirs(dirpath_dst, exist_ok=True)
# NOTE: unfortunately this can't be `blender_thumbnailer_bin` because GNOME calls the command
# with wrapper that means the command *must* be in the users `$PATH`.
# and it cannot be a SYMLINK.
if shutil.which("bwrap") is not None:
command = BLENDER_THUMBNAILER_FILENAME
else:
command = blender_thumbnailer_bin
with open(filepath_thumbnailer_dst, "w", encoding="utf-8") as fh:
fh.write("[Thumbnailer Entry]\n")
fh.write("TryExec={:s}\n".format(command))
fh.write("Exec={:s} %i %o\n".format(command))
fh.write("MimeType={:s};\n".format(BLENDER_MIME))
return None
def handle_mime_association_xml(do_register: bool, all_users: bool) -> Optional[str]:
# `xdg-mime install x-blender.xml`
filename = "x-blender.xml"
if all_users:
base_dir = os.path.join(SYSTEM_PREFIX, "share")
else:
base_dir = XDG_DATA_HOME
# Ensure directories exist `xdg-mime` will fail with an error if these don't exist.
for dirpath_dst in (
os.path.join(base_dir, "mime", "application"),
os.path.join(base_dir, "mime", "packages")
):
os.makedirs(dirpath_dst, exist_ok=True)
del dirpath_dst
# Unfortunately there doesn't seem to be a way to know the installed location.
# Use hard-coded location.
package_xml_dst = os.path.join(base_dir, "mime", "application", filename)
if VERBOSE:
sys.stdout.write("- {:s} mime type: {:s}\n".format(
("Setup" if do_register else "Remove"),
filepath_repr(package_xml_dst),
))
env = {
**os.environ,
"XDG_DATA_DIRS": os.path.join(SYSTEM_PREFIX, "share")
}
if not do_register:
if not os.path.exists(package_xml_dst):
return None
# NOTE: `xdg-mime query default application/x-blender` could be used to check
# if the XML is installed, however there is some slim chance the XML is installed
# but the default doesn't point to Blender, just uninstall as it's harmless.
cmd = (
XDG_MIME_PROG,
"uninstall",
"--mode", "system" if all_users else "user",
package_xml_dst,
)
subprocess.check_output(cmd, env=env)
return None
with tempfile.TemporaryDirectory() as tempdir:
package_xml_src = os.path.join(tempdir, filename)
with open(package_xml_src, mode="w", encoding="utf-8") as fh:
fh.write("""<?xml version="1.0" encoding="UTF-8"?>\n""")
fh.write("""<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">\n""")
fh.write(""" <mime-type type="{:s}">\n""".format(BLENDER_MIME))
# NOTE: not using a trailing full-stop seems to be the convention here.
fh.write(""" <comment>Blender scene</comment>\n""")
fh.write(""" <glob pattern="*.blend"/>\n""")
# TODO: this doesn't seem to work, GNOME's Nautilus & KDE's Dolphin
# already have a file-type icon for this so we might consider this low priority.
if False:
fh.write(""" <icon name="application-x-blender"/>\n""")
fh.write(""" </mime-type>\n""")
fh.write("""</mime-info>\n""")
cmd = (
XDG_MIME_PROG,
"install",
"--mode", "system" if all_users else "user",
package_xml_src,
)
subprocess.check_output(cmd, env=env)
return None
def handle_mime_association_default(do_register: bool, all_users: bool) -> Optional[str]:
# `xdg-mime default blender.desktop application/x-blender`
if VERBOSE:
sys.stdout.write("- {:s} mime type as default\n".format(
("Setup" if do_register else "Remove"),
))
# NOTE: there doesn't seem to be a way to reverse this action.
if not do_register:
return None
cmd = (
XDG_MIME_PROG,
"default",
BLENDER_DESKTOP,
BLENDER_MIME,
)
subprocess.check_output(cmd)
return None
def handle_icon(do_register: bool, all_users: bool) -> Optional[str]:
filename = "blender.svg"
if all_users:
base_dir = os.path.join(SYSTEM_PREFIX, "share")
else:
base_dir = XDG_DATA_HOME
dirpath_dst = os.path.join(base_dir, "icons", "hicolor", "scalable", "apps")
filepath_desktop_src = os.path.join(BLENDER_DIR, filename)
filepath_desktop_dst = os.path.join(dirpath_dst, filename)
if VERBOSE:
sys.stdout.write("- {:s} icon: {:s}\n".format(
("Setup" if do_register else "Remove"),
filepath_repr(filepath_desktop_dst),
))
filepath_ensure_removed(filepath_desktop_dst)
if not do_register:
return None
if not os.path.exists(filepath_desktop_src):
sys.stderr.write(" Icon file not found, skipping: \"{:s}\"\n".format(filepath_desktop_src))
# Not an error.
return None
os.makedirs(dirpath_dst, exist_ok=True)
with open(filepath_desktop_src, "rb") as fh:
data = fh.read()
with open(filepath_desktop_dst, "wb") as fh:
fh.write(data)
return None
# -----------------------------------------------------------------------------
# Escalate Privileges
def main_run_as_root(do_register: bool) -> Optional[str]:
# If the system prefix doesn't exist, fail with an error because it's highly likely that the
# system won't use this when it has not been created.
if not os.path.exists(SYSTEM_PREFIX):
return "Error: system path does not exist {!r}".format(SYSTEM_PREFIX)
prog: Optional[str] = shutil.which("pkexec")
if prog is None:
return "Error: command \"pkexec\" not found"
cmd = [
prog,
sys.executable,
# Skips users `site-packages`.
"-s",
__file__,
BLENDER_BIN,
"--action={:s}".format("register-allusers" if do_register else "unregister-allusers"),
]
if VERBOSE:
sys.stdout.write("Executing: {:s}\n".format(shlex.join(cmd)))
proc = subprocess.run(cmd, stderr=subprocess.PIPE)
if proc.returncode != 0:
if proc.stderr:
return proc.stderr.decode("utf-8", errors="surrogateescape")
return "Error: pkexec returned non-zero returncode"
return None
# -----------------------------------------------------------------------------
# Checked Call
#
# While exceptions should not happen, we can't entirely prevent this as it's always possible
# a file write fails or a command doesn't work as expected anymore.
# Handle these cases gracefully.
def call_handle_checked(
fn: Callable[[bool, bool], Optional[str]],
*,
do_register: bool,
all_users: bool
) -> Optional[str]:
try:
result = fn(do_register, all_users)
except BaseException as ex:
# This should never happen.
result = "Internal Error: {!r}".format(ex)
return result
# -----------------------------------------------------------------------------
# Main Registration Functions
def register_impl(do_register: bool, all_users: bool) -> Optional[str]:
# A non-empty string indicates an error (which is forwarded to the user), otherwise None for success.
global BLENDER_BIN
global BLENDER_DIR
if BLENDER_ENV:
# Only use of `bpy`.
BLENDER_BIN = os.path.normpath(__import__("bpy").app.binary_path)
# Running inside Blender, detect the need for privilege escalation (which will run outside of Blender).
if all_users:
if os.geteuid() != 0:
# Run this script with escalated privileges.
return main_run_as_root(do_register)
else:
assert BLENDER_BIN != ""
BLENDER_DIR = os.path.dirname(BLENDER_BIN)
if all_users:
if not os.access(SYSTEM_PREFIX, os.W_OK):
return "Error: {:s} not writable, this command may need to run as a superuser!".format(SYSTEM_PREFIX)
if VERBOSE:
sys.stdout.write("{:s}: {:s}\n".format("Register" if do_register else "Unregister", BLENDER_BIN))
if XDG_MIME_PROG == "":
return "Could not find \"xdg-mime\", unable to associate mime-types"
handlers = (
handle_bin,
handle_icon,
handle_desktop_file,
handle_mime_association_xml,
# This only makes sense for users, although there may be a way to do this for all users.
*(() if all_users else (handle_mime_association_default,)),
# The thumbnailer only works when installed for all users.
*((handle_thumbnailer,) if all_users else ()),
)
error_or_none = None
for i, fn in enumerate(handlers):
if (error_or_none := call_handle_checked(fn, do_register=do_register, all_users=all_users)) is not None:
break
if error_or_none is not None:
# Roll back registration on failure.
if do_register:
for fn in reversed(handlers[:i + 1]):
error_or_none_reverse = call_handle_checked(fn, do_register=False, all_users=all_users)
if error_or_none_reverse is not None:
sys.stdout.write("Error reverting action: {:s}\n".format(error_or_none_reverse))
# Print to the `stderr`, in case the user has a console open, it can be helpful
# especially if it's multi-line.
sys.stdout.write("{:s}\n".format(error_or_none))
return error_or_none
def register(all_users: bool = False) -> Optional[str]:
# Return an empty string for success.
return register_impl(True, all_users)
def unregister(all_users: bool = False) -> Optional[str]:
# Return an empty string for success.
return register_impl(False, all_users)
# -----------------------------------------------------------------------------
# Running directly (Escalated Privileges)
#
# Needed when running as an administer.
register_actions = {
"register": (True, False),
"unregister": (False, False),
"register-allusers": (True, True),
"unregister-allusers": (False, True),
}
def argparse_create() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser()
parser.add_argument(
"blender_bin",
metavar="BLENDER_BIN",
type=str,
help="The location of Blender's binary",
)
parser.add_argument(
"--action",
choices=register_actions.keys(),
dest="register_action",
required=True,
)
return parser
def main() -> int:
global BLENDER_BIN
assert BLENDER_BIN == ""
args = argparse_create().parse_args()
BLENDER_BIN = args.blender_bin
do_register, all_users = register_actions[args.register_action]
if do_register:
result = register(all_users=all_users)
else:
result = unregister(all_users=all_users)
if result:
sys.stderr.write("{:s}\n".format(result))
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@ -667,15 +667,22 @@ class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
@classmethod
def poll(cls, _context):
# Only for Windows so far
import sys
return sys.platform[:3] == "win"
# macOS isn't supported.
from sys import platform
if platform == "darwin":
return False
return True
def draw_centered(self, context, layout):
if context.preferences.system.is_microsoft_store_install:
layout.label(text="Microsoft Store installation")
layout.label(text="Use Windows 'Default Apps' to associate with blend files")
else:
from sys import platform
associate_supported = True
if platform[:3] == "win":
if context.preferences.system.is_microsoft_store_install:
layout.label(text="Microsoft Store installation")
layout.label(text="Use Windows 'Default Apps' to associate with blend files")
associate_supported = False
if associate_supported:
layout.label(text="Open blend files with this Blender version")
split = layout.split(factor=0.5)
split.alignment = 'LEFT'

View File

@ -58,11 +58,6 @@ struct BMEditMesh {
/** Temp variables for x-mirror editing (-1 when the layer does not exist). */
int mirror_cdlayer;
/**
* Enable for evaluated copies, causes the edit-mesh to free the memory, not its contents.
*/
char is_shallow_copy;
/**
* ID data is older than edit-mode data.
* Set #Main.is_memfile_undo_flush_needed when enabling.

View File

@ -123,8 +123,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
int corners_num,
CustomData_MeshMasks mask);
void BKE_mesh_eval_delete(Mesh *mesh_eval);
/**
* Performs copy for use during evaluation,
* optional referencing original arrays to reduce memory.

View File

@ -111,11 +111,16 @@ struct MeshRuntime {
const ImplicitSharingInfo *face_offsets_sharing_info = nullptr;
/**
* Storage of the edit mode mesh. If it exists, it generally has the most up-to-date
* information about the mesh.
* Storage of the edit mode BMesh with some extra data for quick access in edit mode.
* - For original (non-evaluated) meshes, when it exists, it generally has the most up-to-date
* information about the mesh. That's because this is only allocated in edit mode.
* - For evaluated meshes, this just references the BMesh from an original object in edit mode.
* Conceptually this is a weak pointer for evaluated meshes. In other words, it doesn't have
* ownership over the BMesh, and using `shared_ptr` is just a convenient way to avoid copying
* the whole struct and making sure the reference is valid.
* \note When the object is available, the preferred access method is #BKE_editmesh_from_object.
*/
BMEditMesh *edit_mesh = nullptr;
std::shared_ptr<BMEditMesh> edit_mesh;
/**
* A cache of bounds shared between data-blocks with unchanged positions. When changing positions

View File

@ -7,6 +7,8 @@
* \ingroup bke
*/
#include <memory>
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
@ -14,7 +16,7 @@ struct BMEditMesh;
struct CustomData_MeshMasks;
struct Mesh;
Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
Mesh *BKE_mesh_wrapper_from_editmesh(std::shared_ptr<BMEditMesh> em,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings);
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh);

View File

@ -1009,7 +1009,6 @@ static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
BMEditMesh *em_input,
const CustomData_MeshMasks *dataMask,
/* return args */
Mesh **r_cage,
@ -1017,6 +1016,8 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
GeometrySet **r_geometry_set)
{
Mesh *mesh_input = (Mesh *)ob->data;
BMEditMesh *em_input = mesh_input->runtime->edit_mesh.get();
Mesh *mesh_cage = nullptr;
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
GeometrySet geometry_set_final;
@ -1049,7 +1050,8 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
Mesh *mesh_final = BKE_mesh_wrapper_from_editmesh(em_input, &final_datamask, mesh_input);
Mesh *mesh_final = BKE_mesh_wrapper_from_editmesh(
mesh_input->runtime->edit_mesh, &final_datamask, mesh_input);
int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true);
if (r_cage && cageIndex == -1) {
@ -1094,9 +1096,7 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
* cage mesh isn't modified anymore. */
mesh_final = BKE_mesh_copy_for_eval(mesh_final);
if (mesh_cage->runtime->edit_mesh) {
mesh_final->runtime->edit_mesh = static_cast<BMEditMesh *>(
MEM_dupallocN(mesh_cage->runtime->edit_mesh));
mesh_final->runtime->edit_mesh->is_shallow_copy = true;
mesh_final->runtime->edit_mesh = mesh_cage->runtime->edit_mesh;
mesh_final->runtime->is_original_bmesh = true;
if (mesh_cage->runtime->edit_data) {
mesh_final->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>(
@ -1288,7 +1288,6 @@ static void mesh_build_data(Depsgraph *depsgraph,
static void editbmesh_build_data(Depsgraph *depsgraph,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
{
Mesh *mesh = static_cast<Mesh *>(obedit->data);
@ -1297,13 +1296,13 @@ static void editbmesh_build_data(Depsgraph *depsgraph,
GeometrySet *non_mesh_components;
editbmesh_calc_modifiers(
depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
depsgraph, scene, obedit, dataMask, &me_cage, &me_final, &non_mesh_components);
/* The modifier stack result is expected to share edit mesh pointer with the input.
* This is similar `mesh_calc_finalize()`. */
BKE_mesh_free_editmesh(me_final);
BKE_mesh_free_editmesh(me_cage);
me_final->runtime->edit_mesh = me_cage->runtime->edit_mesh = em;
me_final->runtime->edit_mesh = me_cage->runtime->edit_mesh = mesh->runtime->edit_mesh;
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
* with is in edit mode).
@ -1407,14 +1406,13 @@ void makeDerivedMesh(Depsgraph *depsgraph,
* `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
* object mode, and then user in another scene moves object to edit mode. */
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
if (em) {
editbmesh_build_data(depsgraph, scene, ob, em, &cddata_masks);
if (mesh->runtime->edit_mesh) {
editbmesh_build_data(depsgraph, scene, ob, &cddata_masks);
}
else {
mesh_build_data(depsgraph, scene, ob, &cddata_masks, need_mapping);
@ -1428,7 +1426,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
BMEditMesh *em = ((Mesh *)ob->data)->runtime->edit_mesh;
BMEditMesh *em = ((Mesh *)ob->data)->runtime->edit_mesh.get();
if (em != nullptr) {
/* There is no such a concept as deformed mesh in edit mode.
* Explicitly disallow this request so that the evaluated result is not modified with evaluated
@ -1502,7 +1500,7 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
BMEditMesh * /*em*/,
const CustomData_MeshMasks *dataMask)
{
CustomData_MeshMasks cddata_masks = *dataMask;
@ -1515,7 +1513,7 @@ Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
if (!obedit->runtime->editmesh_eval_cage ||
!CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks))
{
editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
editbmesh_build_data(depsgraph, scene, obedit, &cddata_masks);
}
return obedit->runtime->editmesh_eval_cage;

View File

@ -58,8 +58,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
case ID_ME: {
Mesh *mesh = (Mesh *)id;
BMEditMesh *em = mesh->runtime->edit_mesh;
if (em != nullptr) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMesh *bm = em->bm;
info[int(AttrDomain::Point)].customdata = &bm->vdata;
info[int(AttrDomain::Point)].length = bm->totvert;
@ -326,7 +325,7 @@ CustomDataLayer *BKE_id_attribute_new(ID *id,
if (GS(id->name) == ID_ME) {
Mesh *mesh = reinterpret_cast<Mesh *>(id);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
if (!mesh_edit_mode_attribute_valid(name, domain, type, reports)) {
return nullptr;
}
@ -376,9 +375,8 @@ CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList
if (GS(id->name) == ID_ME) {
Mesh *mesh = reinterpret_cast<Mesh *>(id);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (mesh->runtime->edit_mesh) {
BLI_assert_unreachable();
UNUSED_VARS(em);
return nullptr;
}
}
@ -457,7 +455,7 @@ bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
if (GS(id->name) == ID_ME) {
Mesh *mesh = reinterpret_cast<Mesh *>(id);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (CustomData *data = info[domain].customdata) {
const std::string name_copy = name;

View File

@ -273,7 +273,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(
cd_mask_extra = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, nullptr);
mesh = BKE_mesh_wrapper_from_editmesh(em, &cd_mask_extra, me_input);
mesh = BKE_mesh_wrapper_from_editmesh(
std::make_shared<BMEditMesh>(*em), &cd_mask_extra, me_input);
deformcos.reinitialize(verts_num);
BKE_mesh_wrapper_vert_coords_copy(mesh, deformcos);
deformmats.reinitialize(verts_num);

View File

@ -63,7 +63,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
return ((Mesh *)ob->data)->runtime->edit_mesh;
return ((Mesh *)ob->data)->runtime->edit_mesh.get();
}
void BKE_editmesh_looptris_calc_ex(BMEditMesh *em, const BMeshCalcTessellation_Params *params)

View File

@ -1285,7 +1285,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac
totvert = mesh->verts_num;
if (mesh->runtime->edit_mesh && mesh->runtime->edit_mesh->bm->totvert == totvert) {
em = mesh->runtime->edit_mesh;
em = mesh->runtime->edit_mesh.get();
}
}
else if (ob->type == OB_LATTICE) {

View File

@ -219,7 +219,7 @@ bool BKE_view_layer_filter_edit_mesh_has_uvs(const Object *ob, void * /*user_dat
{
if (ob->type == OB_MESH) {
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
if (const BMEditMesh *em = mesh->runtime->edit_mesh) {
if (const BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
if (CustomData_has_layer(&em->bm->ldata, CD_PROP_FLOAT2)) {
return true;
}
@ -232,7 +232,7 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const Object *ob, void * /*user_d
{
if (ob->type == OB_MESH) {
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
if (const BMEditMesh *em = mesh->runtime->edit_mesh) {
if (const BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
if (em->bm->totedge != 0) {
return true;
}

View File

@ -204,15 +204,7 @@ static void mesh_copy_data(Main *bmain,
void BKE_mesh_free_editmesh(Mesh *mesh)
{
if (mesh->runtime->edit_mesh == nullptr) {
return;
}
if (mesh->runtime->edit_mesh->is_shallow_copy == false) {
BKE_editmesh_free_data(mesh->runtime->edit_mesh);
}
MEM_freeN(mesh->runtime->edit_mesh);
mesh->runtime->edit_mesh = nullptr;
mesh->runtime->edit_mesh.reset();
}
static void mesh_free_data(ID *id)
@ -848,15 +840,6 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
me_src, verts_num, edges_num, 0, faces_num, corners_num, CD_MASK_EVERYTHING);
}
void BKE_mesh_eval_delete(Mesh *mesh_eval)
{
/* Evaluated mesh may point to edit mesh, but never owns it. */
mesh_eval->runtime->edit_mesh = nullptr;
mesh_free_data(&mesh_eval->id);
BKE_libblock_free_data(&mesh_eval->id, false);
MEM_freeN(mesh_eval);
}
Mesh *BKE_mesh_copy_for_eval(const Mesh *source)
{
return reinterpret_cast<Mesh *>(
@ -1155,8 +1138,7 @@ void BKE_mesh_material_remap(Mesh *mesh, const uint *remap, uint remap_len)
} \
((void)0)
if (mesh->runtime->edit_mesh) {
BMEditMesh *em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMIter iter;
BMFace *efa;
@ -1462,7 +1444,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
if (mesh->runtime->mesh_eval != nullptr) {
mesh->runtime->mesh_eval->runtime->edit_mesh = nullptr;
BKE_id_free(nullptr, mesh->runtime->mesh_eval);
mesh->runtime->mesh_eval = nullptr;
}

View File

@ -36,7 +36,7 @@ void BKE_mesh_foreach_mapped_vert(
MeshForeachFlag flag)
{
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMesh *bm = em->bm;
BMIter iter;
BMVert *eve;
@ -94,7 +94,7 @@ void BKE_mesh_foreach_mapped_edge(
void *user_data)
{
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMesh *bm = em->bm;
BMIter iter;
BMEdge *eed;
@ -153,7 +153,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
* we want to always access `dm->loopData`, `EditDerivedBMesh` would
* return loop data from BMesh itself. */
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMesh *bm = em->bm;
BMIter iter;
BMFace *efa;
@ -233,7 +233,7 @@ void BKE_mesh_foreach_mapped_face_center(
{
using namespace blender;
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMesh *bm = em->bm;
BMFace *efa;
BMIter iter;

View File

@ -36,7 +36,6 @@ namespace blender::bke {
static void free_mesh_eval(MeshRuntime &mesh_runtime)
{
if (mesh_runtime.mesh_eval != nullptr) {
mesh_runtime.mesh_eval->runtime->edit_mesh = nullptr;
BKE_id_free(nullptr, mesh_runtime.mesh_eval);
mesh_runtime.mesh_eval = nullptr;
}

View File

@ -52,7 +52,7 @@
using blender::float3;
using blender::Span;
Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
Mesh *BKE_mesh_wrapper_from_editmesh(std::shared_ptr<BMEditMesh> em,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings)
{
@ -68,8 +68,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
/* Use edit-mesh directly where possible. */
mesh->runtime->is_original_bmesh = true;
mesh->runtime->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em));
mesh->runtime->edit_mesh->is_shallow_copy = true;
mesh->runtime->edit_mesh = std::move(em);
/* Make sure we crash if these are ever used. */
#ifndef NDEBUG
@ -110,7 +109,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
BLI_assert(mesh->runtime->edit_mesh != nullptr);
BLI_assert(mesh->runtime->edit_data != nullptr);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BM_mesh_bm_to_me_for_eval(*em->bm, *mesh, &mesh->runtime->cd_mask_extra);
/* Adding original index layers here assumes that all BMesh Mesh wrappers are created from

View File

@ -63,7 +63,7 @@ static void multiresModifier_disp_run(
void multires_customdata_delete(Mesh *mesh)
{
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
/* CustomData_external_remove is used here only to mark layer
* as non-external for further freeing, so zero element count
* looks safer than `em->bm->totface`. */
@ -512,7 +512,7 @@ void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *o
Mesh *mesh = static_cast<Mesh *>(ob->data);
const MDisps *mdisp;
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
mdisp = static_cast<const MDisps *>(CustomData_get_layer(&em->bm->ldata, CD_MDISPS));
}
else {

View File

@ -1639,7 +1639,7 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->runtime->editmesh_eval_cage &&
ob->runtime->editmesh_eval_cage != reinterpret_cast<Mesh *>(ob->runtime->data_eval))
{
BKE_mesh_eval_delete(ob->runtime->editmesh_eval_cage);
BKE_id_free(nullptr, ob->runtime->editmesh_eval_cage);
}
ob->runtime->editmesh_eval_cage = nullptr;
@ -1647,7 +1647,7 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->runtime->is_data_eval_owned) {
ID *data_eval = ob->runtime->data_eval;
if (GS(data_eval->name) == ID_ME) {
BKE_mesh_eval_delete((Mesh *)data_eval);
BKE_id_free(nullptr, (Mesh *)data_eval);
}
else {
BKE_libblock_free_data(data_eval, false);
@ -1659,7 +1659,7 @@ void BKE_object_free_derived_caches(Object *ob)
}
if (ob->runtime->mesh_deform_eval != nullptr) {
Mesh *mesh_deform_eval = ob->runtime->mesh_deform_eval;
BKE_mesh_eval_delete(mesh_deform_eval);
BKE_id_free(nullptr, mesh_deform_eval);
ob->runtime->mesh_deform_eval = nullptr;
}
@ -1806,8 +1806,7 @@ char *BKE_object_data_editmode_flush_ptr_get(ID *id)
const short type = GS(id->name);
switch (type) {
case ID_ME: {
BMEditMesh *em = ((Mesh *)id)->runtime->edit_mesh;
if (em != nullptr) {
if (BMEditMesh *em = ((Mesh *)id)->runtime->edit_mesh.get()) {
return &em->needs_flush_to_id;
}
break;
@ -3087,7 +3086,7 @@ static void give_parvert(const Object *par, int nr, float vec[3])
if (par->type == OB_MESH) {
const Mesh *mesh = (const Mesh *)par->data;
const BMEditMesh *em = mesh->runtime->edit_mesh;
const BMEditMesh *em = mesh->runtime->edit_mesh.get();
const Mesh *mesh_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
BKE_object_get_evaluated_mesh(par);

View File

@ -149,8 +149,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
if (ob->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
if (mesh->runtime->edit_mesh) {
BMEditMesh *em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
if (cd_dvert_offset != -1) {
@ -345,7 +344,7 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
/* Else, make sure that any groups with higher indices are adjusted accordingly */
else if (ob->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
BMIter iter;

View File

@ -291,7 +291,9 @@ static void deg_debug_graphviz_relation_arrowhead(const Relation *rel, dot::Dire
OperationNode *op_from = (OperationNode *)rel->from;
OperationNode *op_to = (OperationNode *)rel->to;
if (op_from->owner->type == NodeType::COPY_ON_EVAL &&
!op_to->owner->need_tag_cow_before_update())
/* The #ID::recalc flag depends on run-time state which is not valid at this point in time.
* Pass in all flags although there may be a better way to represent this. */
!op_to->owner->need_tag_cow_before_update(ID_RECALC_ALL))
{
shape = shape_no_cow;
}

View File

@ -296,7 +296,7 @@ void depsgraph_tag_component(Depsgraph *graph,
}
}
/* If component depends on copy-on-evaluation, tag it as well. */
if (component_node->need_tag_cow_before_update()) {
if (component_node->need_tag_cow_before_update(IDRecalcFlag(id_node->id_cow->recalc))) {
depsgraph_id_tag_copy_on_write(graph, id_node, update_source);
}
if (component_type == NodeType::COPY_ON_EVAL) {
@ -531,8 +531,12 @@ void deg_graph_tag_parameters_if_needed(Main *bmain,
}
/* Clear flags which are known to not affect parameters usable by drivers. */
const uint clean_flags = flags & ~(ID_RECALC_SYNC_TO_EVAL | ID_RECALC_SELECT |
ID_RECALC_BASE_FLAGS | ID_RECALC_SHADING);
const uint clean_flags = flags &
~(ID_RECALC_SYNC_TO_EVAL | ID_RECALC_SELECT | ID_RECALC_BASE_FLAGS |
ID_RECALC_SHADING |
/* While drivers may use the current-frame, this value is assigned
* explicitly and doesn't require a the scene to be copied again. */
ID_RECALC_FRAME_CHANGE);
if (clean_flags == 0) {
/* Changes are limited to only things which are not usable by drivers. */

View File

@ -132,7 +132,7 @@ struct ComponentNode : public Node {
/* Denotes whether copy-on-eval component is to be tagged when this component
* is tagged for update. */
virtual bool need_tag_cow_before_update()
virtual bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/)
{
return true;
}
@ -170,7 +170,7 @@ struct ComponentNode : public Node {
#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
virtual bool need_tag_cow_before_update() \
virtual bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/) \
{ \
return false; \
} \
@ -204,7 +204,6 @@ DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Hierarchy);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Instancing);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Scene);
@ -226,7 +225,7 @@ struct BoneComponentNode : public ComponentNode {
/* Eventually we would not tag parameters in all cases.
* Support for this each ID needs to be added on an individual basis. */
struct ParametersComponentNode : public ComponentNode {
virtual bool need_tag_cow_before_update() override
virtual bool need_tag_cow_before_update(const IDRecalcFlag /*tag*/) override
{
if (ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(owner->id_type)) {
/* Disabled as this is not true for newly added objects, needs investigation. */
@ -239,6 +238,18 @@ struct ParametersComponentNode : public ComponentNode {
DEG_COMPONENT_NODE_DECLARE;
};
/* Audio component. */
struct AudioComponentNode : public ComponentNode {
virtual bool need_tag_cow_before_update(const IDRecalcFlag tag) override
{
/* Frame change doesn't require a copy of the scene, doing so can be a heavy operation
* especially when the collection contains many objects, see #104798. */
return (tag != ID_RECALC_FRAME_CHANGE);
}
DEG_COMPONENT_NODE_DECLARE;
};
void deg_register_component_depsnodes();
} // namespace blender::deg

View File

@ -137,9 +137,6 @@
#define SUBSURFACE_RADIANCE_FORMAT GPU_R11F_G11F_B10F
#define SUBSURFACE_OBJECT_ID_FORMAT GPU_R16UI
/* Minimum visibility size. */
#define LIGHTPROBE_FILTER_VIS_GROUP_SIZE 16
/* Film. */
#define FILM_GROUP_SIZE 16

View File

@ -667,6 +667,7 @@ void IrradianceBake::sync()
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
pass.bind_resources(inst_.uniform_data);
pass.bind_resources(inst_.lights);
pass.bind_resources(inst_.shadows);
/* Sync with the surfel creation stage. */
@ -750,6 +751,7 @@ void IrradianceBake::sync()
pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_OFFSET));
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.bind_ssbo("list_start_buf", &list_start_buf_);
pass.bind_ssbo("list_info_buf", &list_info_buf_);
pass.bind_image("cluster_list_img", &cluster_list_tx_);
pass.bind_image("virtual_offset_img", &virtual_offset_tx_);

View File

@ -144,11 +144,14 @@ void WorldVolumePipeline::sync(GPUMaterial *gpumat)
world_ps_.material_set(*inst_.manager, gpumat);
/* Bind correct dummy texture for attributes defaults. */
volume_sub_pass(world_ps_, nullptr, nullptr, gpumat);
PassSimple::Sub *sub = volume_sub_pass(world_ps_, nullptr, nullptr, gpumat);
world_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
/* Sync with object property pass. */
world_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
is_valid_ = (sub != nullptr);
if (is_valid_) {
world_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
/* Sync with object property pass. */
world_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
}
void WorldVolumePipeline::render(View &view)

View File

@ -84,7 +84,9 @@ static inline void volume_call(
{
if (matpass.sub_pass != nullptr) {
PassMain::Sub *object_pass = volume_sub_pass(*matpass.sub_pass, scene, ob, matpass.gpumat);
object_pass->draw(geom, res_handle);
if (object_pass != nullptr) {
object_pass->draw(geom, res_handle);
}
}
}
@ -359,7 +361,9 @@ void SyncModule::sync_volume(Object *ob, ObjectHandle & /*ob_handle*/, ResourceH
}
PassMain::Sub *object_pass = volume_sub_pass(
*matpass.sub_pass, inst_.scene, ob, matpass.gpumat);
object_pass->draw(geom, res_handle);
if (object_pass != nullptr) {
object_pass->draw(geom, res_handle);
}
};
drawcall_add(material.volume_occupancy, geom, res_handle);

View File

@ -236,7 +236,7 @@ static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob
bool has_skin_roots = false;
/* TODO: Should be its own function. */
Mesh *mesh = (Mesh *)ob->data;
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);

View File

@ -178,7 +178,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
/* TODO: Should be its own function. */
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
if (is_edit_mode) {
BLI_assert(mesh->runtime->edit_mesh);
BLI_assert(mesh->runtime->edit_mesh.get());
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);

View File

@ -79,7 +79,7 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
{
using namespace blender::draw;
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);

View File

@ -597,7 +597,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
BLI_assert(editmesh_eval_cage && editmesh_eval_final);
mr->bm = mesh->runtime->edit_mesh->bm;
mr->edit_bmesh = mesh->runtime->edit_mesh;
mr->edit_bmesh = mesh->runtime->edit_mesh.get();
mr->mesh = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
mr->edit_data = is_mode_active ? mr->mesh->runtime->edit_data.get() : nullptr;

View File

@ -259,7 +259,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
DRWTextStore *dt = DRW_text_cache_ensure();
const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE;
const Mesh *mesh = BKE_object_get_editmesh_eval_cage(ob);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
float v1[3], v2[3], v3[3], vmid[3], fvec[3];
char numstr[32]; /* Stores the measurement display text here */
size_t numstr_len;

View File

@ -182,7 +182,7 @@ static bke::GeometrySet get_original_geometry_eval_copy(Object &object)
}
case OB_MESH: {
const Mesh *mesh = static_cast<const Mesh *>(object.data);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (std::shared_ptr<BMEditMesh> &em = mesh->runtime->edit_mesh) {
Mesh *mesh_copy = BKE_mesh_wrapper_from_editmesh(em, nullptr, mesh);
BKE_mesh_wrapper_ensure_mdata(mesh_copy);
Mesh *final_copy = BKE_mesh_copy_for_eval(mesh_copy);
@ -253,7 +253,7 @@ static void store_result_geometry(
BKE_object_material_from_eval_data(&bmain, &object, &new_mesh->id);
if (object.mode == OB_MODE_EDIT) {
EDBM_mesh_make_from_mesh(&object, new_mesh, scene.toolsettings->selectmode, true);
BKE_editmesh_looptris_and_normals_calc(mesh.runtime->edit_mesh);
BKE_editmesh_looptris_and_normals_calc(mesh.runtime->edit_mesh.get());
BKE_id_free(nullptr, new_mesh);
}
else {

View File

@ -38,17 +38,12 @@
#include "eyedropper_intern.hh"
struct Colorband_RNAUpdateCb {
PointerRNA ptr;
PropertyRNA *prop;
};
namespace blender::ui {
struct EyedropperColorband {
int event_xy_last[2];
/* Alpha is currently fixed at 1.0, may support in future. */
float (*color_buffer)[4];
int color_buffer_alloc;
int color_buffer_len;
Vector<float4> color_buffer;
bool sample_start;
ColorBand init_color_band;
ColorBand *color_band;
@ -88,8 +83,8 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
}
if (band) {
rna_update_ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr;
rna_update_prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop;
rna_update_ptr = but->rnapoin;
rna_update_prop = but->rnaprop;
is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
}
}
@ -110,11 +105,7 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
return false;
}
EyedropperColorband *eye = MEM_cnew<EyedropperColorband>(__func__);
eye->color_buffer_alloc = 16;
eye->color_buffer = static_cast<float(*)[4]>(
MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__));
eye->color_buffer_len = 0;
EyedropperColorband *eye = MEM_new<EyedropperColorband>(__func__, EyedropperColorband{});
eye->color_band = band;
eye->init_color_band = *eye->color_band;
eye->ptr = rna_update_ptr;
@ -131,16 +122,10 @@ static void eyedropper_colorband_sample_point(bContext *C,
const int m_xy[2])
{
if (eye->event_xy_last[0] != m_xy[0] || eye->event_xy_last[1] != m_xy[1]) {
float col[4];
float4 col;
col[3] = 1.0f; /* TODO: sample alpha */
eyedropper_color_sample_fl(C, m_xy, col);
if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) {
eye->color_buffer_alloc *= 2;
eye->color_buffer = static_cast<float(*)[4]>(
MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc));
}
copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col);
eye->color_buffer_len += 1;
eye->color_buffer.append(col);
copy_v2_v2_int(eye->event_xy_last, m_xy);
eye->is_set = true;
}
@ -173,8 +158,7 @@ static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
if (op->customdata) {
EyedropperColorband *eye = static_cast<EyedropperColorband *>(op->customdata);
MEM_freeN(eye->color_buffer);
MEM_freeN(eye);
MEM_delete(eye);
op->customdata = nullptr;
}
}
@ -184,8 +168,10 @@ static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
EyedropperColorband *eye = static_cast<EyedropperColorband *>(op->customdata);
/* Always filter, avoids noise in resulting color-band. */
const bool filter_samples = true;
BKE_colorband_init_from_table_rgba(
eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples);
BKE_colorband_init_from_table_rgba(eye->color_band,
reinterpret_cast<const float(*)[4]>(eye->color_buffer.data()),
eye->color_buffer.size(),
filter_samples);
eye->is_set = true;
if (eye->prop) {
RNA_property_update(C, &eye->ptr, eye->prop);
@ -256,15 +242,15 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w
eyedropper_colorband_exit(C, op);
return OPERATOR_FINISHED;
case EYE_MODAL_POINT_REMOVE_LAST:
if (eye->color_buffer_len > 0) {
eye->color_buffer_len -= 1;
if (!eye->color_buffer.is_empty()) {
eye->color_buffer.pop_last();
eyedropper_colorband_apply(C, op);
}
break;
case EYE_MODAL_POINT_SAMPLE:
eyedropper_colorband_sample_point(C, eye, event->xy);
eyedropper_colorband_apply(C, op);
if (eye->color_buffer_len == MAXCOLORBAND) {
if (eye->color_buffer.size() == MAXCOLORBAND) {
eyedropper_colorband_exit(C, op);
return OPERATOR_FINISHED;
}
@ -274,7 +260,7 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w
if (eye->prop) {
RNA_property_update(C, &eye->ptr, eye->prop);
}
eye->color_buffer_len = 0;
eye->color_buffer.clear();
break;
}
}
@ -367,3 +353,5 @@ void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot)
/* properties */
}
} // namespace blender::ui

View File

@ -1488,8 +1488,10 @@ void UI_OT_eyedropper_color(wmOperatorType *ot);
/* interface_eyedropper_colorband.c */
namespace blender::ui {
void UI_OT_eyedropper_colorramp(wmOperatorType *ot);
void UI_OT_eyedropper_colorramp_point(wmOperatorType *ot);
} // namespace blender::ui
/* interface_eyedropper_datablock.c */

View File

@ -2594,6 +2594,7 @@ static void UI_OT_drop_material(wmOperatorType *ot)
void ED_operatortypes_ui()
{
using namespace blender::ui;
WM_operatortype_append(UI_OT_copy_data_path_button);
WM_operatortype_append(UI_OT_copy_as_driver_button);
WM_operatortype_append(UI_OT_copy_python_command_button);

View File

@ -3742,6 +3742,8 @@ static void colorband_buttons_layout(uiLayout *layout,
bt = uiDefBut(
block, UI_BTYPE_COLORBAND, 0, "", xs, ys, BLI_rctf_size_x(butr), UI_UNIT_Y, coba, 0, 0, "");
bt->rnapoin = cb.ptr;
bt->rnaprop = cb.prop;
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
row = uiLayoutRow(layout, false);

View File

@ -39,7 +39,7 @@ static int set_sharpness_by_angle_exec(bContext *C, wmOperator *op)
for (Object *object : objects) {
Mesh &mesh = *static_cast<Mesh *>(object->data);
BMEditMesh *em = mesh.runtime->edit_mesh;
BMEditMesh *em = mesh.runtime->edit_mesh.get();
bool changed = false;
BMIter iter;

View File

@ -3678,7 +3678,7 @@ static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
scene, view_layer, CTX_wm_view3d(C));
for (Object *obedit : objects) {
Mesh *mesh = static_cast<Mesh *>(obedit->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
if (em->bm->totvertsel == 0) {
continue;
@ -3757,7 +3757,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
Mesh *me_ref = static_cast<Mesh *>(obedit_ref->data);
Key *key_ref = me_ref->key;
KeyBlock *kb_ref = nullptr;
BMEditMesh *em_ref = me_ref->runtime->edit_mesh;
BMEditMesh *em_ref = me_ref->runtime->edit_mesh.get();
BMVert *eve;
BMIter iter;
const Scene *scene = CTX_data_scene(C);
@ -3793,7 +3793,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
Mesh *mesh = static_cast<Mesh *>(obedit->data);
Key *key = mesh->key;
KeyBlock *kb = nullptr;
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
int shape;
if (em->bm->totvertsel == 0) {

View File

@ -843,7 +843,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em)
ob->shapenr = um->shapenr;
MEM_freeN(em_tmp);
MEM_delete(em_tmp);
#ifdef USE_ARRAY_STORE
um_arraystore_expand_clear(um);
@ -947,11 +947,8 @@ static bool mesh_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
elem->obedit_ref.ptr = ob;
Mesh *mesh = static_cast<Mesh *>(elem->obedit_ref.ptr->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
undomesh_from_editmesh(&elem->data,
mesh->runtime->edit_mesh,
mesh->key,
um_references ? um_references[i] : nullptr);
BMEditMesh *em = mesh->runtime->edit_mesh.get();
undomesh_from_editmesh(&elem->data, em, mesh->key, um_references ? um_references[i] : nullptr);
em->needs_flush_to_id = 1;
us->step.data_size += elem->data.undo_size;
elem->data.uv_selectmode = ts->uv_selectmode;
@ -997,7 +994,7 @@ static void mesh_undosys_step_decode(
obedit->id.name);
continue;
}
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
undomesh_to_editmesh(&elem->data, obedit, em);
em->needs_flush_to_id = 1;
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);

View File

@ -278,19 +278,20 @@ void EDBM_mesh_make_from_mesh(Object *ob,
if (mesh->runtime->edit_mesh) {
/* this happens when switching shape keys */
EDBM_mesh_free_data(mesh->runtime->edit_mesh);
MEM_freeN(mesh->runtime->edit_mesh);
EDBM_mesh_free_data(mesh->runtime->edit_mesh.get());
mesh->runtime->edit_mesh.reset();
}
/* Executing operators re-tessellates,
* so we can avoid doing here but at some point it may need to be added back. */
mesh->runtime->edit_mesh = BKE_editmesh_create(bm);
mesh->runtime->edit_mesh = std::make_shared<BMEditMesh>();
mesh->runtime->edit_mesh->bm = bm;
mesh->runtime->edit_mesh->selectmode = mesh->runtime->edit_mesh->bm->selectmode = select_mode;
mesh->runtime->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
/* we need to flush selection because the mode may have changed from when last in editmode */
EDBM_selectmode_flush(mesh->runtime->edit_mesh);
EDBM_selectmode_flush(mesh->runtime->edit_mesh.get());
}
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
@ -1653,7 +1654,7 @@ void EDBM_stats_update(BMEditMesh *em)
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
{
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
/* Order of calling isn't important. */
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);

View File

@ -175,9 +175,7 @@ static void mesh_uv_reset_mface(const blender::IndexRange face, float2 *mloopuv)
void ED_mesh_uv_loop_reset_ex(Mesh *mesh, const int layernum)
{
BMEditMesh *em = mesh->runtime->edit_mesh;
if (em) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
/* Collect BMesh UVs */
const int cd_loop_uv_offset = CustomData_get_n_offset(
&em->bm->ldata, CD_PROP_FLOAT2, layernum);
@ -225,7 +223,6 @@ int ED_mesh_uv_add(
{
/* NOTE: keep in sync with #ED_mesh_color_add. */
BMEditMesh *em;
int layernum_dst;
if (!name) {
@ -235,9 +232,7 @@ int ED_mesh_uv_add(
const std::string unique_name = BKE_id_attribute_calc_unique_name(mesh->id, name);
bool is_init = false;
if (mesh->runtime->edit_mesh) {
em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_PROP_FLOAT2);
if (layernum_dst >= MAX_MTFACE) {
BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
@ -366,12 +361,9 @@ bool *ED_mesh_uv_map_pin_layer_ensure(Mesh *mesh, const int uv_index)
void ED_mesh_uv_ensure(Mesh *mesh, const char *name)
{
BMEditMesh *em;
int layernum_dst;
if (mesh->runtime->edit_mesh) {
em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_PROP_FLOAT2);
if (layernum_dst == 0) {
ED_mesh_uv_add(mesh, name, true, true, nullptr);
@ -401,7 +393,7 @@ int ED_mesh_color_add(
const char *active_name = mesh->active_color_attribute;
if (const CustomDataLayer *active_layer = BKE_id_attributes_color_find(&mesh->id, active_name))
{
if (const BMEditMesh *em = mesh->runtime->edit_mesh) {
if (const BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMesh &bm = *em->bm;
const int src_i = CustomData_get_named_layer(&bm.ldata, CD_PROP_BYTE_COLOR, active_name);
const int dst_i = CustomData_get_named_layer(&bm.ldata, CD_PROP_BYTE_COLOR, layer->name);
@ -754,7 +746,7 @@ static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperato
{
Mesh *mesh = ED_mesh_context(C);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMesh &bm = *em->bm;
if (!CustomData_has_layer(&bm.ldata, CD_CUSTOMLOOPNORMAL)) {
return OPERATOR_CANCELLED;

View File

@ -33,7 +33,7 @@ static struct {
void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
const bool use_em = (!mesh_eval && em && mesh->runtime->edit_mesh == em);
const bool use_em = (!mesh_eval && em && mesh->runtime->edit_mesh.get() == em);
const int totvert = use_em ? em->bm->totvert :
mesh_eval ? mesh_eval->verts_num :
mesh->verts_num;

View File

@ -832,7 +832,7 @@ BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
if (mesh_eval != nullptr) {
mesh_mirror = mesh_eval;
}
else if (BMEditMesh *em = mesh->runtime->edit_mesh) {
else if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
em_mirror = em;
}
else {
@ -972,7 +972,7 @@ int ED_mesh_mirror_get_vert(Object *ob, int index)
bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
int index_mirr;
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMVert *eve, *eve_mirr;
eve = BM_vert_at_index(em->bm, index);
eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology);

View File

@ -1217,7 +1217,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
}
}
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
/* Copy to bmesh. */
const int active_color_offset = CustomData_get_offset_named(
&em->bm->vdata, eCustomDataType(active_color_layer->type), active_color_layer->name);
@ -1252,7 +1252,7 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
MEM_SAFE_FREE(num_loops_for_vertex);
}
else if (domain == bke::AttrDomain::Corner) {
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
/* Copy to bmesh. */
const int active_color_offset = CustomData_get_offset_named(
&em->bm->ldata, eCustomDataType(active_color_layer->type), active_color_layer->name);

View File

@ -583,9 +583,8 @@ static bool editmode_load_free_ex(Main *bmain,
}
if (free_data) {
EDBM_mesh_free_data(mesh->runtime->edit_mesh);
MEM_freeN(mesh->runtime->edit_mesh);
mesh->runtime->edit_mesh = nullptr;
EDBM_mesh_free_data(mesh->runtime->edit_mesh.get());
mesh->runtime->edit_mesh.reset();
}
/* will be recalculated as needed. */
{

View File

@ -132,7 +132,7 @@ static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name,
static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMVert *eve;
BMIter iter;
int index = 0, nr = 0;
@ -340,7 +340,7 @@ static bool object_hook_index_array(Main *bmain,
DEG_id_tag_update(static_cast<ID *>(obedit->data), 0);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BKE_editmesh_looptris_and_normals_calc(em);

View File

@ -122,7 +122,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *
BKE_object_eval_reset(ob_eval);
if (ob->type == OB_MESH) {
Mesh *mesh_eval = mesh_create_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_DERIVEDMESH);
BKE_mesh_eval_delete(mesh_eval);
BKE_id_free(nullptr, mesh_eval);
}
else if (ob->type == OB_LATTICE) {
BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval);
@ -2687,7 +2687,7 @@ void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
static void modifier_skin_customdata_delete(Object *ob)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BM_data_layer_free(em->bm, &em->bm->vdata, CD_MVERT_SKIN);
}
else {

View File

@ -130,7 +130,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(static_cast<ID *>(obedit->data), 0);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BKE_editmesh_looptris_and_normals_calc(em);

View File

@ -1316,7 +1316,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (obedit) {
if (obedit->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(obedit->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMVert *eve;
BMIter iter;

View File

@ -157,7 +157,7 @@ bool vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const
case ID_ME: {
Mesh *mesh = (Mesh *)id;
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMesh *bm = em->bm;
const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
BMIter iter;
@ -525,7 +525,7 @@ static void ED_mesh_defvert_mirror_update_em(
Object *ob, BMVert *eve, int def_nr, int vidx, const int cd_dvert_offset)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMVert *eve_mirr;
bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@ -563,7 +563,7 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
void vgroup_vert_active_mirror(Object *ob, int def_nr)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
MDeformVert *dvert_act;
if (mesh->symmetry & ME_SYMMETRY_X) {
@ -599,7 +599,7 @@ static void vgroup_remove_weight(Object *ob, const int def_nr)
static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BMVert *eve_act;
int v_act;
MDeformVert *dvert_act;
@ -638,13 +638,12 @@ static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
{
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
MDeformVert *dvert_act;
int i, vgroup_tot, subset_count;
const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(
ob, subset_type, &vgroup_tot, &subset_count);
if (em) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
BMIter iter;
BMVert *eve, *eve_act;
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
@ -935,8 +934,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum)
if (ob->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
if (mesh->runtime->edit_mesh) {
BMEditMesh *em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
/* warning, this lookup is _not_ fast */
@ -1020,8 +1018,7 @@ static void vgroup_select_verts(Object *ob, int select)
if (ob->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
if (mesh->runtime->edit_mesh) {
BMEditMesh *em = mesh->runtime->edit_mesh;
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
if (cd_dvert_offset != -1) {
@ -2037,9 +2034,8 @@ void vgroup_mirror(Object *ob,
/* only the active group */
if (ob->type == OB_MESH) {
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
if (em) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
BMIter iter;
@ -2231,7 +2227,7 @@ static void vgroup_assign_verts(Object *ob, const float weight)
Mesh *mesh = static_cast<Mesh *>(ob->data);
if (mesh->runtime->edit_mesh) {
BMEditMesh *em = mesh->runtime->edit_mesh;
BMEditMesh *em = mesh->runtime->edit_mesh.get();
int cd_dvert_offset;
BMIter iter;
@ -3873,10 +3869,9 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
MDeformVert *dvert_act;
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh;
int i;
if (em) {
if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
BMIter iter;
BMVert *eve, *eve_act;

View File

@ -2147,7 +2147,7 @@ static void fill_mesh_color(Mesh &mesh,
const bool use_face_sel,
const bool affect_alpha)
{
if (BMEditMesh *em = mesh.runtime->edit_mesh) {
if (BMEditMesh *em = mesh.runtime->edit_mesh.get()) {
BMesh *bm = em->bm;
const std::string name = attribute_name;
const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh.id, name.c_str());

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