From 32c687b5ec43463d7d419313c4eecf1ad629f61e Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Tue, 10 Aug 2021 11:27:18 -0600 Subject: Clean-up: Remove UTF8-BOM markers Done at the request of Sergey. --- source/blender/blenkernel/intern/icons.cc | 2 +- source/blender/blenkernel/intern/mesh.c | 2 +- source/blender/io/alembic/intern/abc_reader_object.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 12a0a1e3ae7..5a4b2448a73 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index b04988a8035..18274d4023f 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index 00b73d29c5c..d136d8c3e91 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 -- cgit v1.2.3 From 8652e69d8bd0ad3a6dcc6c1bbacfaf826df56744 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 10 Aug 2021 12:33:47 -0500 Subject: Fix T90447: 3D view transform locks do not use driver colors Caused by rB6942dd9f4900. --- source/blender/editors/space_view3d/view3d_buttons.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 3428a738dde..b79303551a1 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1456,7 +1456,7 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "location", 0, NULL, ICON_NONE); colsub = uiLayoutColumn(split, true); - uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE_OR_STATUS); uiItemL(colsub, "", ICON_NONE); uiItemR(colsub, ptr, @@ -1472,7 +1472,7 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_quaternion", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); - uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE_OR_STATUS); uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE); if (RNA_boolean_get(ptr, "lock_rotations_4d")) { uiItemR(colsub, @@ -1496,7 +1496,7 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_axis_angle", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); - uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE_OR_STATUS); uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE); if (RNA_boolean_get(ptr, "lock_rotations_4d")) { uiItemR(colsub, @@ -1520,7 +1520,7 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_euler", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); - uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE_OR_STATUS); uiItemL(colsub, "", ICON_NONE); uiItemR(colsub, ptr, @@ -1536,7 +1536,7 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "scale", 0, NULL, ICON_NONE); colsub = uiLayoutColumn(split, true); - uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE_OR_STATUS); uiItemL(colsub, "", ICON_NONE); uiItemR(colsub, ptr, -- cgit v1.2.3 From fcd2d63b644edc9ad6a3be4b0fdbd41428a7392a Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 10 Aug 2021 18:05:48 -0300 Subject: Fix 'GPU_matrix_unproject_3fv' not working with out-of-bounds points To solve this, the unproject code was redone in order to simplify and optimize. --- .../blender/editors/space_view3d/view3d_project.c | 2 +- source/blender/gpu/GPU_matrix.h | 6 +- source/blender/gpu/intern/gpu_matrix.cc | 122 +++++++-------------- .../windowmanager/gizmo/intern/wm_gizmo_map.c | 8 +- 4 files changed, 46 insertions(+), 92 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index d926ea84e0f..88efc530484 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -843,7 +843,7 @@ bool ED_view3d_unproject_v3( const int viewport[4] = {0, 0, region->winx, region->winy}; const float region_co[3] = {regionx, regiony, regionz}; - return GPU_matrix_unproject_3fv(region_co, rv3d->viewmat, rv3d->winmat, viewport, world); + return GPU_matrix_unproject_3fv(region_co, rv3d->viewinv, rv3d->winmat, viewport, world); } /** \} */ diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h index e073263f352..edf16f04349 100644 --- a/source/blender/gpu/GPU_matrix.h +++ b/source/blender/gpu/GPU_matrix.h @@ -131,15 +131,11 @@ void GPU_matrix_project_2fv(const float world[3], float r_win[2]); bool GPU_matrix_unproject_3fv(const float win[3], - const float model[4][4], + const float model_inverted[4][4], const float proj[4][4], const int view[4], float r_world[3]); -void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc, - const float win[3], - float r_world[3]); - /* 2D Projection Matrix */ void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top); diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index efa04568401..e277dda3812 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -513,93 +513,55 @@ void GPU_matrix_project_2fv(const float world[3], win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; } -/** - * The same result could be obtained as follows: - * - * \code{.c} - * float projinv[4][4]; - * invert_m4_m4(projinv, projmat); - * co[0] = 2 * co[0] - 1; - * co[1] = 2 * co[1] - 1; - * co[2] = 2 * co[2] - 1; - * mul_project_m4_v3(projinv, co); - * \endcode - * - * But that solution loses much precision. - * Therefore, get the same result without inverting the matrix. - */ -static void gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc( - const struct GPUMatrixUnproject_Precalc *precalc, float co[3]) -{ - /* 'precalc->dims' is the result of 'projmat_dimensions(proj, ...)'. */ - co[0] = (float)scalenormd(precalc->dims.xmin, precalc->dims.xmax, co[0]); - co[1] = (float)scalenormd(precalc->dims.ymin, precalc->dims.ymax, co[1]); - - if (precalc->is_persp) { - co[2] = (precalc->dims.zmax * precalc->dims.zmin) / - (precalc->dims.zmax + co[2] * (precalc->dims.zmin - precalc->dims.zmax)); - co[0] *= co[2] / precalc->dims.zmin; - co[1] *= co[2] / precalc->dims.zmin; - } - else { - co[2] = (float)scalenormd(precalc->dims.zmin, precalc->dims.zmax, co[2]); - } - co[2] *= -1; -} - -bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc, - const float model[4][4], - const float proj[4][4], - const int view[4]) -{ - precalc->is_persp = proj[3][3] == 0.0f; - projmat_dimensions_db(proj, - &precalc->dims.xmin, - &precalc->dims.xmax, - &precalc->dims.ymin, - &precalc->dims.ymax, - &precalc->dims.zmin, - &precalc->dims.zmax); - if (isinf(precalc->dims.zmax)) { - /* We cannot retrieve the actual value of the clip_end. - * Use `FLT_MAX` to avoid NAN's. */ - precalc->dims.zmax = FLT_MAX; - } - for (int i = 0; i < 4; i++) { - precalc->view[i] = (float)view[i]; - } - if (!invert_m4_m4(precalc->model_inverted, model)) { - unit_m4(precalc->model_inverted); - return false; - } - return true; -} - -void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc, - const float win[3], - float r_world[3]) -{ - float in[3] = { - (win[0] - precalc->view[0]) / precalc->view[2], - (win[1] - precalc->view[1]) / precalc->view[3], - win[2], - }; - gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc(precalc, in); - mul_v3_m4v3(r_world, precalc->model_inverted, in); -} - bool GPU_matrix_unproject_3fv(const float win[3], - const float model[4][4], + const float model_inverted[4][4], const float proj[4][4], const int view[4], float r_world[3]) { - struct GPUMatrixUnproject_Precalc precalc; - if (!GPU_matrix_unproject_precalc(&precalc, model, proj, view)) { - zero_v3(r_world); + zero_v3(r_world); + float in[3] = { + 2 * ((win[0] - view[0]) / view[2]) - 1.0f, + 2 * ((win[1] - view[1]) / view[3]) - 1.0f, + 2 * win[2] - 1.0f, + }; + + /** + * The same result could be obtained as follows: + * + * \code{.c} + * float projinv[4][4]; + * invert_m4_m4(projinv, projview); + * copy_v3_v3(r_world, in); + * mul_project_m4_v3(projinv, r_world); + * \endcode + * + * But that solution loses much precision. + * Therefore, get the same result without inverting the project view matrix. + */ + + float out[3]; + const bool is_persp = proj[3][3] == 0.0f; + if (is_persp) { + out[2] = proj[3][2] / (proj[2][2] + in[2]); + if (isinf(out[2])) { + out[2] = FLT_MAX; + } + out[0] = out[2] * ((proj[2][0] + in[0]) / proj[0][0]); + out[1] = out[2] * ((proj[2][1] + in[1]) / proj[1][1]); + out[2] *= -1; + } + else { + out[0] = (-proj[3][0] + in[0]) / proj[0][0]; + out[1] = (-proj[3][1] + in[1]) / proj[1][1]; + out[2] = (-proj[3][2] + in[2]) / proj[2][2]; + } + + if (!is_finite_v3(out)) { return false; } - GPU_matrix_unproject_3fv_with_precalc(&precalc, win, r_world); + + mul_v3_m4v3(r_world, model_inverted, out); return true; } diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 5ec26a7b208..b90e288776e 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -616,11 +616,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, const int viewport[4] = {0, 0, region->winx, region->winy}; float co_3d_origin[3]; - /* Avoid multiple calculations. */ - struct GPUMatrixUnproject_Precalc unproj_precalc; - GPU_matrix_unproject_precalc(&unproj_precalc, rv3d->viewmat, rv3d->winmat, viewport); - - GPU_matrix_unproject_3fv_with_precalc(&unproj_precalc, co_screen, co_3d_origin); + GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); uint *buf_iter = buffer; int hit_found = -1; @@ -631,7 +627,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, wmGizmo *gz = visible_gizmos[buf_iter[3] >> 8]; float co_3d[3]; co_screen[2] = int_as_float(buf_iter[1]); - GPU_matrix_unproject_3fv_with_precalc(&unproj_precalc, co_screen, co_3d); + GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); float select_bias = gz->select_bias; if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { select_bias *= gz->scale_final; -- cgit v1.2.3 From 55615e2600735d83c2332dbc18a8553d3d5e5cfd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 10:11:11 +1000 Subject: Cleanup: trailing space, remove BOM --- source/blender/gpu/intern/gpu_matrix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index e277dda3812..bbcc241f5e3 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -560,7 +560,7 @@ bool GPU_matrix_unproject_3fv(const float win[3], if (!is_finite_v3(out)) { return false; } - + mul_v3_m4v3(r_world, model_inverted, out); return true; } -- cgit v1.2.3 From d480f03952a13355eb3f4ad2dbc0df332d6aff67 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 10:11:12 +1000 Subject: Cleanup: clang-format --- source/blender/compositor/operations/COM_BilateralBlurOperation.h | 4 +--- source/blender/gpu/tests/gpu_shader_test.cc | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.h b/source/blender/compositor/operations/COM_BilateralBlurOperation.h index 4819715deb0..517c5292827 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.h +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.h @@ -58,9 +58,7 @@ class BilateralBlurOperation : public MultiThreadedOperation, public QualityStep this->m_space = data->sigma_space + data->iter; } - void get_area_of_interest(int input_idx, - const rcti &output_area, - rcti &r_input_area) override; + void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override; void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/gpu_shader_test.cc index 561858f421e..dbe336af097 100644 --- a/source/blender/gpu/tests/gpu_shader_test.cc +++ b/source/blender/gpu/tests/gpu_shader_test.cc @@ -108,7 +108,8 @@ void main() { EXPECT_NE(shader, nullptr); /* Construct Texture. */ - GPUTexture *texture = GPU_texture_create_1d("gpu_shader_compute_1d", SIZE, 0, GPU_RGBA32F, nullptr); + GPUTexture *texture = GPU_texture_create_1d( + "gpu_shader_compute_1d", SIZE, 0, GPU_RGBA32F, nullptr); EXPECT_NE(texture, nullptr); GPU_shader_bind(shader); -- cgit v1.2.3 From 2f39f7f81549cff0285c2f1934de5d2c743785d4 Mon Sep 17 00:00:00 2001 From: Henrik Dick Date: Wed, 11 Aug 2021 10:22:49 +1000 Subject: Modifier: use high quality normals for vertex offset Using high quality normals for vertex offset when set for higher precision offsets. This was only used for calculating even-offset. Reviewed By: campbellbarton Ref D12176 --- .../modifiers/intern/MOD_solidify_extrude.c | 47 +++++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'source/blender') diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index e97190b1878..64e1eb92fda 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -507,8 +507,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex /* NOTE: copied vertex layers don't have flipped normals yet. do this after applying offset. */ if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { /* no even thickness, very simple */ - float scalar_short; - float scalar_short_vgroup; + float ofs_new_vgroup; /* for clamping */ float *vert_lens = NULL; @@ -597,7 +596,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex uint i_orig, i_end; bool do_shell_align; - scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; + ofs_new_vgroup = ofs_new; INIT_VERT_ARRAY_OFFSETS(false); @@ -606,36 +605,40 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) { - scalar_short_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index); + ofs_new_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index); } else { - scalar_short_vgroup = BKE_defvert_find_weight(dv, defgrp_index); + ofs_new_vgroup = BKE_defvert_find_weight(dv, defgrp_index); } - scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * - scalar_short; + ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_new; } if (do_clamp && offset > FLT_EPSILON) { /* always reset because we may have set before */ if (dvert == NULL) { - scalar_short_vgroup = scalar_short; + ofs_new_vgroup = ofs_new; } if (do_angle_clamp) { float cos_ang = cosf(((2 * M_PI) - vert_angs[i]) * 0.5f); if (cos_ang > 0) { float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang; if (max_off < offset * 0.5f) { - scalar_short_vgroup *= max_off / offset * 2; + ofs_new_vgroup *= max_off / offset * 2; } } } else { if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; - scalar_short_vgroup *= scalar; + ofs_new_vgroup *= scalar; } } } - madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); + if (vert_nors) { + madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup); + } + else { + madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f); + } } } @@ -643,7 +646,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex uint i_orig, i_end; bool do_shell_align; - scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; + ofs_new_vgroup = ofs_orig; /* as above but swapped */ INIT_VERT_ARRAY_OFFSETS(true); @@ -653,36 +656,40 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) { - scalar_short_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index); + ofs_new_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index); } else { - scalar_short_vgroup = BKE_defvert_find_weight(dv, defgrp_index); + ofs_new_vgroup = BKE_defvert_find_weight(dv, defgrp_index); } - scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * - scalar_short; + ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_orig; } if (do_clamp && offset > FLT_EPSILON) { /* always reset because we may have set before */ if (dvert == NULL) { - scalar_short_vgroup = scalar_short; + ofs_new_vgroup = ofs_orig; } if (do_angle_clamp) { float cos_ang = cosf(vert_angs[i_orig] * 0.5f); if (cos_ang > 0) { float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang; if (max_off < offset * 0.5f) { - scalar_short_vgroup *= max_off / offset * 2; + ofs_new_vgroup *= max_off / offset * 2; } } } else { if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; - scalar_short_vgroup *= scalar; + ofs_new_vgroup *= scalar; } } } - madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); + if (vert_nors) { + madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup); + } + else { + madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f); + } } } -- cgit v1.2.3 From 18fbcaf7b9273cc4a7e153fea60a53fec956d600 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 16:09:23 +1000 Subject: Cleanup: rename BKE_collection_{free => free_data} This function doesn't free the collection, only it's memory. --- source/blender/blenkernel/BKE_collection.h | 2 +- source/blender/blenkernel/intern/collection.c | 2 +- source/blender/blenkernel/intern/scene.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 8b8d0f7b107..2c7143be60e 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -65,7 +65,7 @@ void BKE_collection_add_from_collection(struct Main *bmain, struct Scene *scene, struct Collection *collection_src, struct Collection *collection_dst); -void BKE_collection_free(struct Collection *collection); +void BKE_collection_free_data(struct Collection *collection); bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy); struct Collection *BKE_collection_duplicate(struct Main *bmain, diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index dbcd80fe065..b62e33ff564 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -508,7 +508,7 @@ void BKE_collection_add_from_collection(Main *bmain, * \{ */ /** Free (or release) any data used by this collection (does not free the collection itself). */ -void BKE_collection_free(Collection *collection) +void BKE_collection_free_data(Collection *collection) { BKE_libblock_free_data(&collection->id, false); collection_free_data(&collection->id); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 9dab276af95..c55185c0f2a 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -445,7 +445,7 @@ static void scene_free_data(ID *id) * for objects directly in the master collection? then other * collections in the scene need to do it too? */ if (scene->master_collection) { - BKE_collection_free(scene->master_collection); + BKE_collection_free_data(scene->master_collection); MEM_freeN(scene->master_collection); scene->master_collection = NULL; } -- cgit v1.2.3 From cbc671947a3baca3da7d6c5a2980a86b7f6a7055 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 16:56:11 +1000 Subject: Fix T88033: Python reference memory leaks for non main data-blocks ID data-blocks that could be accessed from Python and weren't freed using BKE_id_free_ex did not release the Python reference count. Add BKE_libblock_free_data_py function to clear the Python reference in this case. Add asserts to ensure no Python reference is held in situations when ID's are copied for internal use (not exposed through the RNA API), to ensure these kinds of leaks don't go by unnoticed again. --- source/blender/blenkernel/BKE_lib_id.h | 2 ++ source/blender/blenkernel/intern/gpencil.c | 1 + source/blender/blenkernel/intern/lib_id_delete.c | 35 +++++++++++++++++----- source/blender/blenkernel/intern/material.c | 1 + source/blender/blenkernel/intern/node.cc | 1 + source/blender/blenkernel/intern/particle_system.c | 1 + source/blender/blenkernel/intern/scene.c | 1 + source/blender/editors/space_clip/clip_editor.c | 1 + source/blender/gpu/intern/gpu_material.c | 1 + source/blender/nodes/shader/node_shader_tree.c | 1 + source/blender/windowmanager/intern/wm.c | 1 + 11 files changed, 38 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index fac5dc8c010..5de669cb620 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -201,6 +201,8 @@ enum { void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL(); void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL(); +void BKE_libblock_free_data_py(struct ID *id); + void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag); void BKE_id_free(struct Main *bmain, void *idv); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 38397f8f307..f566e18fb2f 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -521,6 +521,7 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval) { BKE_gpencil_free(gpd_eval, true); BKE_libblock_free_data(&gpd_eval->id, false); + BLI_assert(!gpd_eval->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(gpd_eval); } diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index a9407860c06..43afac5a376 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -142,14 +142,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i DEG_id_type_tag(bmain, type); } -#ifdef WITH_PYTHON -# ifdef WITH_PYTHON_SAFETY - BPY_id_release(id); -# endif - if (id->py_instance) { - BPY_DECREF_RNA_INVALIDATE(id->py_instance); - } -#endif + BKE_libblock_free_data_py(id); Key *key = ((flag & LIB_ID_FREE_NO_MAIN) == 0) ? BKE_key_from_id(id) : NULL; @@ -406,3 +399,29 @@ size_t BKE_id_multi_tagged_delete(Main *bmain) { return id_delete(bmain, true); } + +/* -------------------------------------------------------------------- */ +/** \name Python Data Handling + * \{ */ + +/** + * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly + * this function will need to be called too, if Python has access to the data. + * + * ID data-blocks such as #Material.nodetree are not stored in #Main. + */ +void BKE_libblock_free_data_py(ID *id) +{ +#ifdef WITH_PYTHON +# ifdef WITH_PYTHON_SAFETY + BPY_id_release(id); +# endif + if (id->py_instance) { + BPY_DECREF_RNA_INVALIDATE(id->py_instance); + } +#else + UNUSED_VARS(id); +#endif +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 4f0b2a718ed..ca57038f1c4 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1802,6 +1802,7 @@ void BKE_material_copybuf_free(void) { if (matcopybuf.nodetree) { ntreeFreeLocalTree(matcopybuf.nodetree); + BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(matcopybuf.nodetree); matcopybuf.nodetree = NULL; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 1bf95369794..bd22f049a8b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -3194,6 +3194,7 @@ void ntreeFreeEmbeddedTree(bNodeTree *ntree) { ntreeFreeTree(ntree); BKE_libblock_free_data(&ntree->id, true); + BKE_libblock_free_data_py(&ntree->id); } void ntreeFreeLocalTree(bNodeTree *ntree) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index f592b0f97ea..60edb78f8ba 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4761,6 +4761,7 @@ static void particle_settings_free_local(ParticleSettings *particle_settings) { BKE_libblock_free_datablock(&particle_settings->id, 0); BKE_libblock_free_data(&particle_settings->id, false); + BLI_assert(!particle_settings->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(particle_settings); } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index c55185c0f2a..5ecd9b7283e 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -446,6 +446,7 @@ static void scene_free_data(ID *id) * collections in the scene need to do it too? */ if (scene->master_collection) { BKE_collection_free_data(scene->master_collection); + BKE_libblock_free_data_py(&scene->master_collection->id); MEM_freeN(scene->master_collection); scene->master_collection = NULL; } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 67b4fd61d38..834ef847069 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -1037,6 +1037,7 @@ static void prefetch_freejob(void *pjv) if (clip_local != NULL) { BKE_libblock_free_datablock(&clip_local->id, 0); BKE_libblock_free_data(&clip_local->id, false); + BLI_assert(!clip_local->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(clip_local); } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 37089785e0e..56e72fbeca9 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -758,6 +758,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, /* Only free after GPU_pass_shader_get where GPUUniformBuf * read data from the local tree. */ ntreeFreeLocalTree(localtree); + BLI_assert(!localtree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(localtree); /* note that even if building the shader fails in some way, we still keep diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 7367f73d171..98edc133a1d 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -531,6 +531,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree) bNodeTree *ngroup = (bNodeTree *)node->id; ntreeFreeLocalNode(localtree, node); ntreeFreeTree(ngroup); + BLI_assert(!ngroup->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(ngroup); } else { diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 9657f8aa03c..e11ef52eb84 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -628,6 +628,7 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist) wm_close_and_free(C, wm); BLI_remlink(wmlist, wm); BKE_libblock_free_data(&wm->id, true); + BKE_libblock_free_data_py(&wm->id); MEM_freeN(wm); } } -- cgit v1.2.3 From f3e26c847b6ba0924cfd02641345164c54234425 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 17:29:26 +1000 Subject: PyAPI: report unreleased ID's with WITH_PYTHON_SAFETY enabled This would have made T88033 more straightforward to track down. --- source/blender/python/intern/bpy.c | 3 -- source/blender/python/intern/bpy_interface.c | 7 +++- source/blender/python/intern/bpy_rna.c | 53 ++++++++++++++++------------ source/blender/python/intern/bpy_rna.h | 1 + 4 files changed, 38 insertions(+), 26 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 30a61067c9e..0e0f431cb19 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -417,9 +417,6 @@ void BPy_init_modules(struct bContext *C) PyDict_SetItemString(PyImport_GetModuleDict(), "_bpy", mod); Py_DECREF(mod); - /* run first, initializes rna types */ - BPY_rna_init(); - /* needs to be first so bpy_types can run */ PyModule_AddObject(mod, "types", BPY_rna_types()); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 35450e3eaad..945933dd8b7 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -502,7 +502,10 @@ void BPY_python_start(bContext *C, int argc, const char **argv) } #endif - /* bpy.* and lets us import it */ + /* Run first, initializes RNA types. */ + BPY_rna_init(); + + /* Defines `bpy.*` and lets us import it. */ BPy_init_modules(C); pyrna_alloc_types(); @@ -541,6 +544,8 @@ void BPY_python_end(void) /* free other python data. */ pyrna_free_types(); + BPY_rna_exit(); + /* clear all python data from structs */ bpy_intern_string_exit(); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index b83c13e1974..17cbf8e4569 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -181,23 +181,13 @@ static PyMethodDef id_free_weakref_cb_def = { /* Adds a reference to the list, remember to decref. */ static GHash *id_weakref_pool_get(ID *id) { - GHash *weakinfo_hash = NULL; - - if (id_weakref_pool) { - weakinfo_hash = BLI_ghash_lookup(id_weakref_pool, (void *)id); - } - else { - /* First time, allocate pool. */ - id_weakref_pool = BLI_ghash_ptr_new("rna_global_pool"); - weakinfo_hash = NULL; - } - + GHash *weakinfo_hash = BLI_ghash_lookup(id_weakref_pool, (void *)id); if (weakinfo_hash == NULL) { - /* We use a ghash as a set, we could use libHX's HXMAP_SINGULAR, but would be an extra dep. */ + /* This could be a set, values are used to keep a reference back to the ID + * (all of them are the same). */ weakinfo_hash = BLI_ghash_ptr_new("rna_id"); BLI_ghash_insert(id_weakref_pool, id, weakinfo_hash); } - return weakinfo_hash; } @@ -283,14 +273,6 @@ static void id_release_weakref_list(struct ID *id, GHash *weakinfo_hash) BLI_ghash_remove(id_weakref_pool, (void *)id, NULL, NULL); BLI_ghash_free(weakinfo_hash, NULL, NULL); - - if (BLI_ghash_len(id_weakref_pool) == 0) { - BLI_ghash_free(id_weakref_pool, NULL, NULL); - id_weakref_pool = NULL; -# ifdef DEBUG_RNA_WEAKREF - printf("id_release_weakref freeing pool\n"); -# endif - } } static void id_release_weakref(struct ID *id) @@ -310,7 +292,8 @@ void BPY_id_release(struct ID *id) #endif #ifdef USE_PYRNA_INVALIDATE_WEAKREF - if (id_weakref_pool) { + /* Check for NULL since this may run before Python has been started. */ + if (id_weakref_pool != NULL) { PyGILState_STATE gilstate = PyGILState_Ensure(); id_release_weakref(id); @@ -7776,6 +7759,32 @@ void BPY_rna_init(void) return; } #endif + +#ifdef USE_PYRNA_INVALIDATE_WEAKREF + BLI_assert(id_weakref_pool == NULL); + id_weakref_pool = BLI_ghash_ptr_new("rna_global_pool"); +#endif +} + +void BPY_rna_exit(void) +{ +#ifdef USE_PYRNA_INVALIDATE_WEAKREF + /* This can help track down which kinds of data were not released. + * If they were in fact freed by Blender, printing their names + * will crash giving a useful error with address sanitizer. The likely cause + * for this list not being empty is a missing call to: #BKE_libblock_free_data_py. */ + const int id_weakref_pool_len = BLI_ghash_len(id_weakref_pool); + if (id_weakref_pool_len != id_weakref_pool_len) { + printf("Found %d unreleased ID's\n", id_weakref_pool_len); + GHashIterator gh_iter; + GHASH_ITER (gh_iter, id_weakref_pool) { + ID *id = BLI_ghashIterator_getKey(&gh_iter); + printf("ID: %s\n", id->name); + } + } + BLI_ghash_free(id_weakref_pool, NULL, NULL); + id_weakref_pool = NULL; +#endif } /* 'bpy.data' from Python. */ diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 24dbad53eb3..fd468bed470 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -181,6 +181,7 @@ StructRNA *srna_from_self(PyObject *self, const char *error_prefix); StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix); void BPY_rna_init(void); +void BPY_rna_exit(void); PyObject *BPY_rna_module(void); void BPY_update_rna_module(void); // PyObject *BPY_rna_doc(void); -- cgit v1.2.3 From 6aae14027828f8f75d5041a8fb23fce29c66f26d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 11 Aug 2021 11:22:57 +0200 Subject: Cleanup: Minor comment update on `LIB_TAG_NEW`. --- source/blender/makesdna/DNA_ID.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 3995e98f34d..8a577be2749 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -551,7 +551,7 @@ enum { /* tag data-block as having actually increased user-count for the extra virtual user. */ LIB_TAG_EXTRAUSER_SET = 1 << 7, - /* RESET_AFTER_USE tag newly duplicated/copied IDs. + /* RESET_AFTER_USE tag newly duplicated/copied IDs (see #ID_NEW_SET macro above). * Also used internally in readfile.c to mark data-blocks needing do_versions. */ LIB_TAG_NEW = 1 << 8, /* RESET_BEFORE_USE free test flag. -- cgit v1.2.3 From 48ba341d151206a5acfd3c945a9c9ef183c3d0a6 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 11 Aug 2021 13:34:11 +0200 Subject: Cleanup: Keylist Drawing - Split up in multiple functions. --- source/blender/editors/animation/keyframes_draw.c | 322 ++++++++++++++-------- 1 file changed, 203 insertions(+), 119 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index deed79942ac..d858ef3ca5a 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -183,141 +183,210 @@ void draw_keyframe_shape(float x, immVertex2f(pos_id, x, y); } -static void draw_keylist(View2D *v2d, - const struct AnimKeylist *keylist, - float ypos, - float yscale_fac, - bool channelLocked, - int saction_flag) -{ - const float icon_sz = U.widget_unit * 0.5f * yscale_fac; - const float half_icon_sz = 0.5f * icon_sz; - const float smaller_sz = 0.35f * icon_sz; - const float ipo_sz = 0.1f * icon_sz; - const float gpencil_sz = smaller_sz * 0.8f; - const float screenspace_margin = (0.35f * (float)UI_UNIT_X) / UI_view2d_scale_get_x(v2d); +/* Common attributes shared between the draw calls. */ +typedef struct DrawKeylistUIData { + float alpha; + float icon_sz; + float half_icon_sz; + float smaller_sz; + float ipo_sz; + float gpencil_sz; + float screenspace_margin; + float sel_color[4]; + float unsel_color[4]; + float sel_mhcol[4]; + float unsel_mhcol[4]; + float ipo_color[4]; + float ipo_color_mix[4]; + /* Show interpolation and handle type? */ + bool show_ipo; +} DrawKeylistUIData; + +static void draw_keylist_ui_data_init(DrawKeylistUIData *ctx, + View2D *v2d, + float yscale_fac, + bool channel_locked, + eSAction_Flag saction_flag) +{ /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */ /* TODO: allow this opacity factor to be themed? */ - float alpha = channelLocked ? 0.25f : 1.0f; + ctx->alpha = channel_locked ? 0.25f : 1.0f; + + ctx->icon_sz = U.widget_unit * 0.5f * yscale_fac; + ctx->half_icon_sz = 0.5f * ctx->icon_sz; + ctx->smaller_sz = 0.35f * ctx->icon_sz; + ctx->ipo_sz = 0.1f * ctx->icon_sz; + ctx->gpencil_sz = ctx->smaller_sz * 0.8f; + ctx->screenspace_margin = (0.35f * (float)UI_UNIT_X) / UI_view2d_scale_get_x(v2d); + + ctx->show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0; + + UI_GetThemeColor4fv(TH_STRIP_SELECT, ctx->sel_color); + UI_GetThemeColor4fv(TH_STRIP, ctx->unsel_color); + UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ctx->ipo_color); + + ctx->sel_color[3] *= ctx->alpha; + ctx->unsel_color[3] *= ctx->alpha; + ctx->ipo_color[3] *= ctx->alpha; + + copy_v4_v4(ctx->sel_mhcol, ctx->sel_color); + ctx->sel_mhcol[3] *= 0.8f; + copy_v4_v4(ctx->unsel_mhcol, ctx->unsel_color); + ctx->unsel_mhcol[3] *= 0.8f; + copy_v4_v4(ctx->ipo_color_mix, ctx->ipo_color); + ctx->ipo_color_mix[3] *= 0.5f; +} - /* Show interpolation and handle type? */ - bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0; - /* draw keyblocks */ - float sel_color[4], unsel_color[4]; - float sel_mhcol[4], unsel_mhcol[4]; - float ipo_color[4], ipo_color_mix[4]; - - /* cache colors first */ - UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color); - UI_GetThemeColor4fv(TH_STRIP, unsel_color); - UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color); - - sel_color[3] *= alpha; - unsel_color[3] *= alpha; - ipo_color[3] *= alpha; - - copy_v4_v4(sel_mhcol, sel_color); - sel_mhcol[3] *= 0.8f; - copy_v4_v4(unsel_mhcol, unsel_color); - unsel_mhcol[3] *= 0.8f; - copy_v4_v4(ipo_color_mix, ipo_color); - ipo_color_mix[3] *= 0.5f; - - const ListBase *keys = ED_keylist_listbase(keylist); - - LISTBASE_FOREACH (ActKeyColumn *, ab, keys) { - /* Draw grease pencil bars between keyframes. */ - if ((ab->next != NULL) && (ab->block.flag & ACTKEYBLOCK_FLAG_GPENCIL)) { - UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); - float size = 1.0f; - switch (ab->next->key_type) { - case BEZT_KEYTYPE_BREAKDOWN: - case BEZT_KEYTYPE_MOVEHOLD: - case BEZT_KEYTYPE_JITTER: - size *= 0.5f; - break; - case BEZT_KEYTYPE_KEYFRAME: - size *= 0.8f; - break; - default: - break; - } - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = ab->cfra, - .xmax = min_ff(ab->next->cfra - (screenspace_margin * size), ab->next->cfra), - .ymin = ypos - gpencil_sz, - .ymax = ypos + gpencil_sz, - }, - true, - 0.25f * (float)UI_UNIT_X, - (ab->block.sel) ? sel_mhcol : unsel_mhcol); - } - else { - /* Draw other types. */ - UI_draw_roundbox_corner_set(UI_CNR_NONE); - - int valid_hold = actkeyblock_get_valid_hold(ab); - if (valid_hold != 0) { - if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) { - /* draw "moving hold" long-keyframe block - slightly smaller */ - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = ab->cfra, - .xmax = ab->next->cfra, - .ymin = ypos - smaller_sz, - .ymax = ypos + smaller_sz, - }, - true, - 3.0f, - (ab->block.sel) ? sel_mhcol : unsel_mhcol); - } - else { - /* draw standard long-keyframe block */ - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = ab->cfra, - .xmax = ab->next->cfra, - .ymin = ypos - half_icon_sz, - .ymax = ypos + half_icon_sz, - }, - true, - 3.0f, - (ab->block.sel) ? sel_color : unsel_color); - } +static void draw_keylist_block_gpencil(const DrawKeylistUIData *ctx, + const ActKeyColumn *ab, + float ypos) +{ + UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); + float size = 1.0f; + switch (ab->next->key_type) { + case BEZT_KEYTYPE_BREAKDOWN: + case BEZT_KEYTYPE_MOVEHOLD: + case BEZT_KEYTYPE_JITTER: + size *= 0.5f; + break; + case BEZT_KEYTYPE_KEYFRAME: + size *= 0.8f; + break; + default: + break; + } + UI_draw_roundbox_4fv( + &(const rctf){ + .xmin = ab->cfra, + .xmax = min_ff(ab->next->cfra - (ctx->screenspace_margin * size), ab->next->cfra), + .ymin = ypos - ctx->gpencil_sz, + .ymax = ypos + ctx->gpencil_sz, + }, + true, + 0.25f * (float)UI_UNIT_X, + (ab->block.sel) ? ctx->sel_mhcol : ctx->unsel_mhcol); +} + +static void draw_keylist_block_moving_hold(const DrawKeylistUIData *ctx, + const ActKeyColumn *ab, + float ypos) +{ + + UI_draw_roundbox_4fv( + &(const rctf){ + .xmin = ab->cfra, + .xmax = ab->next->cfra, + .ymin = ypos - ctx->smaller_sz, + .ymax = ypos + ctx->smaller_sz, + }, + true, + 3.0f, + (ab->block.sel) ? ctx->sel_mhcol : ctx->unsel_mhcol); +} + +static void draw_keylist_block_standard(const DrawKeylistUIData *ctx, + const ActKeyColumn *ab, + float ypos) +{ + UI_draw_roundbox_4fv( + &(const rctf){ + .xmin = ab->cfra, + .xmax = ab->next->cfra, + .ymin = ypos - ctx->half_icon_sz, + .ymax = ypos + ctx->half_icon_sz, + }, + true, + 3.0f, + (ab->block.sel) ? ctx->sel_color : ctx->unsel_color); +} + +static void draw_keylist_block_interpolation_line(const DrawKeylistUIData *ctx, + const ActKeyColumn *ab, + float ypos) +{ + UI_draw_roundbox_4fv( + &(const rctf){ + .xmin = ab->cfra, + .xmax = ab->next->cfra, + .ymin = ypos - ctx->ipo_sz, + .ymax = ypos + ctx->ipo_sz, + }, + true, + 3.0f, + (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ctx->ipo_color_mix : ctx->ipo_color); +} + +static void draw_keylist_block(const DrawKeylistUIData *ctx, const ActKeyColumn *ab, float ypos) +{ + + /* Draw grease pencil bars between keyframes. */ + if ((ab->next != NULL) && (ab->block.flag & ACTKEYBLOCK_FLAG_GPENCIL)) { + draw_keylist_block_gpencil(ctx, ab, ypos); + } + else { + /* Draw other types. */ + UI_draw_roundbox_corner_set(UI_CNR_NONE); + + int valid_hold = actkeyblock_get_valid_hold(ab); + if (valid_hold != 0) { + if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) { + /* draw "moving hold" long-keyframe block - slightly smaller */ + draw_keylist_block_moving_hold(ctx, ab, ypos); } - if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { - /* draw an interpolation line */ - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = ab->cfra, - .xmax = ab->next->cfra, - .ymin = ypos - ipo_sz, - .ymax = ypos + ipo_sz, - }, - true, - 3.0f, - (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color); + else { + /* draw standard long-keyframe block */ + draw_keylist_block_standard(ctx, ab, ypos); } } + if (ctx->show_ipo && actkeyblock_is_valid(ab) && + (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { + /* draw an interpolation line */ + draw_keylist_block_interpolation_line(ctx, ab, ypos); + } } +} - GPU_blend(GPU_BLEND_ALPHA); +static void draw_keylist_blocks(const DrawKeylistUIData *ctx, + const ListBase * /*ActKeyColumn*/ columns, + float ypos) +{ + LISTBASE_FOREACH (ActKeyColumn *, ab, columns) { + draw_keylist_block(ctx, ab, ypos); + } +} + +static bool draw_keylist_is_visible_key(const View2D *v2d, const ActKeyColumn *ak) +{ + return IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax); +} +static int draw_keylist_visible_key_len(View2D *v2d, const ListBase * /*ActKeyColumn*/ keys) +{ /* count keys */ - uint key_len = 0; + uint len = 0; + LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { /* Optimization: if keyframe doesn't appear within 5 units (screenspace) * in visible area, don't draw. * This might give some improvements, * since we current have to flip between view/region matrices. */ - if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) { - key_len++; + if (draw_keylist_is_visible_key(v2d, ak)) { + len++; } } + return len; +} +static void draw_keylist_keys(const DrawKeylistUIData *ctx, + View2D *v2d, + const ListBase * /*ActKeyColumn*/ keys, + float ypos, + eSAction_Flag saction_flag) +{ + GPU_blend(GPU_BLEND_ALPHA); + const int key_len = draw_keylist_visible_key_len(v2d, keys); if (key_len > 0) { /* draw keys */ GPUVertFormat *format = immVertexFormat(); @@ -338,8 +407,8 @@ static void draw_keylist(View2D *v2d, short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE; LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { - if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) { - if (show_ipo) { + if (draw_keylist_is_visible_key(v2d, ak)) { + if (ctx->show_ipo) { handle_type = ak->handle_type; } if (saction_flag & SACTION_SHOW_EXTREMES) { @@ -348,11 +417,11 @@ static void draw_keylist(View2D *v2d, draw_keyframe_shape(ak->cfra, ypos, - icon_sz, + ctx->icon_sz, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, - alpha, + ctx->alpha, pos_id, size_id, color_id, @@ -371,6 +440,21 @@ static void draw_keylist(View2D *v2d, GPU_blend(GPU_BLEND_NONE); } +static void draw_keylist(View2D *v2d, + const struct AnimKeylist *keylist, + float ypos, + float yscale_fac, + bool channelLocked, + eSAction_Flag saction_flag) +{ + DrawKeylistUIData ctx; + draw_keylist_ui_data_init(&ctx, v2d, yscale_fac, channelLocked, saction_flag); + + const ListBase *columns = ED_keylist_listbase(keylist); + draw_keylist_blocks(&ctx, columns, ypos); + draw_keylist_keys(&ctx, v2d, columns, ypos, saction_flag); +} + /* *************************** Channel Drawing Funcs *************************** */ void draw_summary_channel( -- cgit v1.2.3 From 62cb5c5c4aacc3f83fa5053e4fb5fc4524522fe7 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 11 Aug 2021 14:20:49 +0200 Subject: Enable Asset Browser by default for poses, rest stays experimental Idea for 3.0 is to disable all functionality that isn't well polished and focus on those parts first. Starting with poses. * Adds a new experimental option "Extended Asset Browser", replacing "Asset Browser". * Unlike the previous option, this isn't enabled by default anymore. This didn't work well in practice and caused plenty of confusion. * "Mark as Asset" and "Clear Asset" are hidden if the option is disabled. * Same for the category selection in the Asset Browser. * Always show display the "Only Assets" option in the File Browser while browing inside .blend files. That way you can hide data-blocks that are not pose assets. * The Asset Library setup UI in the Preferences is always visible now, it's needed for pose library access. Addresses T90181, T90180 and T90300. Differential Revision: https://developer.blender.org/D12120 --- source/blender/blenkernel/intern/blendfile.c | 4 ---- .../blender/blenloader/intern/versioning_userdef.c | 7 ------ source/blender/editors/asset/intern/asset_ops.cc | 2 +- .../editors/interface/interface_context_menu.c | 2 +- source/blender/editors/space_file/space_file.c | 26 +++++++++++++++------- source/blender/makesdna/DNA_userdef_types.h | 2 +- source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_userdef.c | 12 +++++----- 8 files changed, 28 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 61827be08e5..1c5d8804280 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -660,10 +660,6 @@ UserDef *BKE_blendfile_userdef_from_defaults(void) BKE_studiolight_default(userdef->light_param, userdef->light_ambient); BKE_preferences_asset_library_default_add(userdef); - /* Enable asset browser features by default for alpha testing. - * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha - * builds. */ - userdef->experimental.use_asset_browser = true; return userdef; } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index c409f0a71fc..0042ff29dc2 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -873,13 +873,6 @@ void blo_do_versions_userdef(UserDef *userdef) } } - if (!USER_VERSION_ATLEAST(293, 2)) { - /* Enable asset browser features by default for alpha testing. - * BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha - * builds. */ - userdef->experimental.use_asset_browser = true; - } - if (!USER_VERSION_ATLEAST(293, 12)) { if (userdef->gizmo_size_navigate_v3d == 0) { userdef->gizmo_size_navigate_v3d = 80; diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index dc418a1b3d5..d69a2cae94d 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -36,7 +36,7 @@ using PointerRNAVec = blender::Vector; static bool asset_operation_poll(bContext * /*C*/) { - return U.experimental.use_asset_browser; + return U.experimental.use_extended_asset_browser; } /** diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index d917534895d..8ace057891d 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -952,7 +952,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev } /* If the button represents an id, it can set the "id" context pointer. */ - if (U.experimental.use_asset_browser && ED_asset_can_mark_single_from_context(C)) { + if (U.experimental.use_extended_asset_browser && ED_asset_can_mark_single_from_context(C)) { ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data; /* Gray out items depending on if data-block is an asset. Preferably this could be done via diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 0b3349f5751..7deaa2fec60 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -334,6 +334,12 @@ static void file_refresh(const bContext *C, ScrArea *area) sfile->files = filelist_new(params->type); params->highlight_file = -1; /* added this so it opens nicer (ton) */ } + + if (!U.experimental.use_extended_asset_browser && ED_fileselect_is_asset_browser(sfile)) { + /* Only poses supported as non-experimental right now. */ + params->filter_id = FILTER_ID_AC; + } + filelist_settype(sfile->files, params->type); filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); @@ -575,6 +581,16 @@ static void file_main_region_message_subscribe(const wmRegionMessageSubscribePar /* All properties for this space type. */ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); } + + /* Experimental Asset Browser features option. */ + { + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_PreferencesExperimental, &U.experimental, &ptr); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "use_extended_asset_browser"); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, prop, &msg_sub_value_area_tag_refresh, __func__); + } } static bool file_main_region_needs_refresh_before_draw(SpaceFile *sfile) @@ -852,13 +868,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C), EnumPropertyItem **item, int *totitem) { - if (U.experimental.use_asset_browser) { - RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items); - } - else { - RNA_enum_items_add_value( - item, totitem, rna_enum_space_file_browse_mode_items, FILE_BROWSE_MODE_FILES); - } + RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items); } static const char *file_context_dir[] = { diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 5f8a8c6230a..28acf5413b8 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -645,7 +645,7 @@ typedef struct UserDef_Experimental { char use_full_frame_compositor; char use_sculpt_vertex_colors; char use_sculpt_tools_tilt; - char use_asset_browser; + char use_extended_asset_browser; char use_override_templates; char _pad[5]; /** `makesdna` does not allow empty structs. */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 97615016016..1eeb68c3a23 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -499,6 +499,7 @@ extern StructRNA RNA_Pose; extern StructRNA RNA_PoseBone; extern StructRNA RNA_Preferences; extern StructRNA RNA_PreferencesEdit; +extern StructRNA RNA_PreferencesExperimental; extern StructRNA RNA_PreferencesFilePaths; extern StructRNA RNA_PreferencesInput; extern StructRNA RNA_PreferencesKeymap; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 2d93715a438..483506d5733 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6297,12 +6297,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Sculpt Mode Tilt Support", "Support for pen tablet tilt events in Sculpt Mode"); - prop = RNA_def_property(srna, "use_asset_browser", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "use_asset_browser", 1); - RNA_def_property_ui_text( - prop, - "Asset Browser", - "Enable Asset Browser editor and operators to manage data-blocks as asset"); + prop = RNA_def_property(srna, "use_extended_asset_browser", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text(prop, + "Extended Asset Browser", + "Enable Asset Browser editor and operators to manage regular " + "data-blocks as assets, not just poses"); + RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1); -- cgit v1.2.3 From bbcb60fb22b375094836e4ab90569db1f73c42e3 Mon Sep 17 00:00:00 2001 From: Michael Kowalski Date: Wed, 11 Aug 2021 09:35:38 -0300 Subject: Fix T90519: USD Exporter Error Fixes: `Error: metersPerUnit does not match retrieved type float` --- source/blender/io/usd/intern/usd_capi_export.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc index 25f12e683cf..efa31df25c1 100644 --- a/source/blender/io/usd/intern/usd_capi_export.cc +++ b/source/blender/io/usd/intern/usd_capi_export.cc @@ -102,7 +102,7 @@ static void export_startjob(void *customdata, usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit, - pxr::VtValue(scene->unit.scale_length)); + static_cast(scene->unit.scale_length)); usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + BKE_blender_version_string()); -- cgit v1.2.3 From 6a9d7139f7d05e0c51827a3a4b862c0547dc0513 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 11 Aug 2021 14:49:17 +0200 Subject: Cleanup: ID management: remove unused old `BKE_libblock_copy_for_localize` function. --- source/blender/blenkernel/BKE_lib_id.h | 2 - source/blender/blenkernel/intern/lib_id.c | 8 - .../blender/blenkernel/intern/mesh_normals.cc.orig | 2217 ++++++++++++++++++++ 3 files changed, 2217 insertions(+), 10 deletions(-) create mode 100644 source/blender/blenkernel/intern/mesh_normals.cc.orig (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 5de669cb620..bb875f8d1c9 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -152,8 +152,6 @@ void BKE_libblock_copy_ex(struct Main *bmain, const int orig_flag); void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -/* Special version: used by data-block localization. */ -void *BKE_libblock_copy_for_localize(const struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 5e1027c62af..0f880d16358 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1321,14 +1321,6 @@ void *BKE_libblock_copy(Main *bmain, const ID *id) return idn; } -/* XXX TODO: get rid of this useless wrapper at some point... */ -void *BKE_libblock_copy_for_localize(const ID *id) -{ - ID *idn; - BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); - return idn; -} - /* ***************** ID ************************ */ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) { diff --git a/source/blender/blenkernel/intern/mesh_normals.cc.orig b/source/blender/blenkernel/intern/mesh_normals.cc.orig new file mode 100644 index 00000000000..18d384e8589 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_normals.cc.orig @@ -0,0 +1,2217 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * + * Mesh normal calculation functions. + * + * \see bmesh_mesh_normals.c for the equivalent #BMesh functionality. + */ + +#include + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_alloca.h" +#include "BLI_bitmap.h" + +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_stack.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "BKE_customdata.h" +#include "BKE_editmesh_cache.h" +#include "BKE_global.h" +#include "BKE_mesh.h" + +<<<<<<< Updated upstream +#include "atomic_ops.h" + +// #define DEBUG_TIME +======= +#define DEBUG_TIME +>>>>>>> Stashed changes + +#ifdef DEBUG_TIME +# include "PIL_time.h" +# include "PIL_time_utildefines.h" +#endif + +static CLG_LogRef LOG = {"bke.mesh_normals"}; + +/* -------------------------------------------------------------------- */ +/** \name Private Utility Functions + * \{ */ + +/** + * A thread-safe version of #add_v3_v3 that uses a spin-lock. + * + * \note Avoid using this when the chance of contention is high. + */ +static void add_v3_v3_atomic(float r[3], const float a[3]) +{ +#define FLT_EQ_NONAN(_fa, _fb) (*((const uint32_t *)&_fa) == *((const uint32_t *)&_fb)) + + float virtual_lock = r[0]; + while (true) { + /* This loops until following conditions are met: + * - `r[0]` has same value as virtual_lock (i.e. it did not change since last try). + * - `r[0]` was not `FLT_MAX`, i.e. it was not locked by another thread. */ + const float test_lock = atomic_cas_float(&r[0], virtual_lock, FLT_MAX); + if (_ATOMIC_LIKELY(FLT_EQ_NONAN(test_lock, virtual_lock) && (test_lock != FLT_MAX))) { + break; + } + virtual_lock = test_lock; + } + virtual_lock += a[0]; + r[1] += a[1]; + r[2] += a[2]; + + /* Second atomic operation to 'release' + * our lock on that vector and set its first scalar value. */ + /* Note that we do not need to loop here, since we 'locked' `r[0]`, + * nobody should have changed it in the mean time. */ + virtual_lock = atomic_cas_float(&r[0], FLT_MAX, virtual_lock); + BLI_assert(virtual_lock == FLT_MAX); + +#undef FLT_EQ_NONAN +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Normal Calculation + * \{ */ + +void BKE_mesh_normals_tag_dirty(Mesh *mesh) +{ + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL; +} + +/** + * Call when there are no polygons. + */ +static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) +{ + for (int i = 0; i < numVerts; i++) { + MVert *mv = &mverts[i]; + float no[3]; + + normalize_v3_v3(no, mv->co); + normal_float_to_short_v3(mv->no, no); + } +} + +/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(), + * and remove the function of the same name below, as that one doesn't seem to be + * called anywhere. */ +void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh) +{ + const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT); + + BKE_mesh_calc_normals_mapping_ex(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->mpoly, + mesh->totloop, + mesh->totpoly, + nullptr, + mesh->mface, + mesh->totface, + nullptr, + nullptr, + only_face_normals); +} + +/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-nullptr + * and vertex normals are stored in actual mverts. + */ +void BKE_mesh_calc_normals_mapping(MVert *mverts, + int numVerts, + const MLoop *mloop, + const MPoly *mpolys, + int numLoops, + int numPolys, + float (*r_polyNors)[3], + const MFace *mfaces, + int numFaces, + const int *origIndexFace, + float (*r_faceNors)[3]) +{ + BKE_mesh_calc_normals_mapping_ex(mverts, + numVerts, + mloop, + mpolys, + numLoops, + numPolys, + r_polyNors, + mfaces, + numFaces, + origIndexFace, + r_faceNors, + false); +} +/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */ +void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, + int numVerts, + const MLoop *mloop, + const MPoly *mpolys, + int numLoops, + int numPolys, + float (*r_polyNors)[3], + const MFace *mfaces, + int numFaces, + const int *origIndexFace, + float (*r_faceNors)[3], + const bool only_face_normals) +{ + float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors; + + if (numPolys == 0) { + if (only_face_normals == false) { + mesh_calc_normals_vert_fallback(mverts, numVerts); + } + return; + } + + /* if we are not calculating verts and no verts were passes then we have nothing to do */ + if ((only_face_normals == true) && (r_polyNors == nullptr) && (r_faceNors == nullptr)) { + CLOG_WARN(&LOG, "called with nothing to do"); + return; + } + + if (!pnors) { + pnors = (float(*)[3])MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__); + } + /* NO NEED TO ALLOC YET */ + /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ + + if (only_face_normals == false) { + /* vertex normals are optional, they require some extra calculations, + * so make them optional */ + BKE_mesh_calc_normals_poly( + mverts, nullptr, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); + } + else { + /* only calc poly normals */ + const MPoly *mp = mpolys; + for (int i = 0; i < numPolys; i++, mp++) { + BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); + } + } + + if (origIndexFace && + /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */ + fnors != nullptr && + numFaces) { + const MFace *mf = mfaces; + for (int i = 0; i < numFaces; i++, mf++, origIndexFace++) { + if (*origIndexFace < numPolys) { + copy_v3_v3(fnors[i], pnors[*origIndexFace]); + } + else { + /* eek, we're not corresponding to polys */ + CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad."); + } + } + } + + if (pnors != r_polyNors) { + MEM_freeN(pnors); + } + /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */ + + fnors = pnors = nullptr; +} + +struct MeshCalcNormalsData { + const MPoly *mpolys; + const MLoop *mloop; + MVert *mverts; + float (*pnors)[3]; + float (*vnors)[3]; +}; + +static void mesh_calc_normals_poly_cb(void *__restrict userdata, + const int pidx, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; + const MPoly *mp = &data->mpolys[pidx]; + + BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]); +} + +static void mesh_calc_normals_poly_and_accum_cb(void *__restrict userdata, + const int pidx, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; + const MPoly *mp = &data->mpolys[pidx]; + const MLoop *ml = &data->mloop[mp->loopstart]; + const MVert *mverts = data->mverts; + float(*vnors)[3] = data->vnors; + + float pnor_temp[3]; + float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; + + const int i_end = mp->totloop - 1; + + /* Polygon Normal and edge-vector */ + /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ + { + zero_v3(pnor); + /* Newell's Method */ + const float *v_curr = mverts[ml[i_end].v].co; + for (int i_next = 0; i_next <= i_end; i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + add_newell_cross_v3_v3v3(pnor, v_curr, v_next); + v_curr = v_next; + } + if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { + pnor[2] = 1.0f; /* other axes set to 0.0 */ + } + } + + /* Accumulate angle weighted face normal into the vertex normal. */ + /* inline version of #accumulate_vertex_normals_poly_v3. */ + { + float edvec_prev[3], edvec_next[3], edvec_end[3]; + const float *v_curr = mverts[ml[i_end].v].co; + sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr); + normalize_v3(edvec_prev); + copy_v3_v3(edvec_end, edvec_prev); + + for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + + /* Skip an extra normalization by reusing the first calculated edge. */ + if (i_next != i_end) { + sub_v3_v3v3(edvec_next, v_curr, v_next); + normalize_v3(edvec_next); + } + else { + copy_v3_v3(edvec_next, edvec_end); + } + + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); + const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; + + add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); + v_curr = v_next; + copy_v3_v3(edvec_prev, edvec_next); + } + } +} + +static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata, + const int vidx, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; + + MVert *mv = &data->mverts[vidx]; + float *no = data->vnors[vidx]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); +} + +void BKE_mesh_calc_normals_poly(MVert *mverts, + float (*r_vertnors)[3], + int numVerts, + const MLoop *mloop, + const MPoly *mpolys, + int UNUSED(numLoops), + int numPolys, + float (*r_polynors)[3], + const bool only_face_normals) +{ + float(*pnors)[3] = r_polynors; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + + if (only_face_normals) { + BLI_assert((pnors != nullptr) || (numPolys == 0)); + BLI_assert(r_vertnors == nullptr); + + MeshCalcNormalsData data; + data.mpolys = mpolys; + data.mloop = mloop; + data.mverts = mverts; + data.pnors = pnors; + + BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings); + return; + } + + float(*vnors)[3] = r_vertnors; + bool free_vnors = false; + + /* first go through and calculate normals for all the polys */ + if (vnors == nullptr) { + vnors = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__); + free_vnors = true; + } + else { + memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts); + } + + MeshCalcNormalsData data; + data.mpolys = mpolys; + data.mloop = mloop; + data.mverts = mverts; + data.pnors = pnors; + data.vnors = vnors; + + /* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */ + BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_and_accum_cb, &settings); + + /* Normalize and validate computed vertex normals (`vnors`). */ + BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); + + if (free_vnors) { + MEM_freeN(vnors); + } +} + +void BKE_mesh_ensure_normals(Mesh *mesh) +{ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(mesh); + } + BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0); +} + +/** + * Called after calculating all modifiers. + */ +void BKE_mesh_ensure_normals_for_display(Mesh *mesh) +{ + switch ((eMeshWrapperType)mesh->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + /* Run code below. */ + break; + case ME_WRAPPER_TYPE_BMESH: { + struct BMEditMesh *em = mesh->edit_mesh; + EditMeshData *emd = mesh->runtime.edit_data; + if (emd->vertexCos) { + BKE_editmesh_cache_ensure_vert_normals(em, emd); + BKE_editmesh_cache_ensure_poly_normals(em, emd); + } + return; + } + } + + float(*poly_nors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); + const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0; + const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || + poly_nors == nullptr); + + if (do_vert_normals || do_poly_normals) { + const bool do_add_poly_nors_cddata = (poly_nors == nullptr); + if (do_add_poly_nors_cddata) { + poly_nors = (float(*)[3])MEM_malloc_arrayN( + (size_t)mesh->totpoly, sizeof(*poly_nors), __func__); + } + + /* calculate poly/vert normals */ + BKE_mesh_calc_normals_poly(mesh->mvert, + nullptr, + mesh->totvert, + mesh->mloop, + mesh->mpoly, + mesh->totloop, + mesh->totpoly, + poly_nors, + !do_vert_normals); + + if (do_add_poly_nors_cddata) { + CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly); + } + + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; + mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; + } +} + +/* Note that this does not update the CD_NORMAL layer, + * but does update the normals in the CD_MVERT layer. */ +void BKE_mesh_calc_normals(Mesh *mesh) +{ +#ifdef DEBUG_TIME + TIMEIT_START_AVERAGED(BKE_mesh_calc_normals); +#endif + BKE_mesh_calc_normals_poly(mesh->mvert, + nullptr, + mesh->totvert, + mesh->mloop, + mesh->mpoly, + mesh->totloop, + mesh->totpoly, + nullptr, + false); +#ifdef DEBUG_TIME + TIMEIT_END_AVERAGED(BKE_mesh_calc_normals); +#endif + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; +} + +void BKE_mesh_calc_normals_looptri(MVert *mverts, + int numVerts, + const MLoop *mloop, + const MLoopTri *looptri, + int looptri_num, + float (*r_tri_nors)[3]) +{ + float(*tnorms)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms"); + float(*fnors)[3] = (r_tri_nors) ? r_tri_nors : + (float(*)[3])MEM_calloc_arrayN( + (size_t)looptri_num, sizeof(*fnors), "meshnormals"); + + if (!tnorms || !fnors) { + goto cleanup; + } + + for (int i = 0; i < looptri_num; i++) { + const MLoopTri *lt = &looptri[i]; + float *f_no = fnors[i]; + const uint vtri[3] = { + mloop[lt->tri[0]].v, + mloop[lt->tri[1]].v, + mloop[lt->tri[2]].v, + }; + + normal_tri_v3(f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co); + + accumulate_vertex_normals_tri_v3(tnorms[vtri[0]], + tnorms[vtri[1]], + tnorms[vtri[2]], + f_no, + mverts[vtri[0]].co, + mverts[vtri[1]].co, + mverts[vtri[2]].co); + } + + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + for (int i = 0; i < numVerts; i++) { + MVert *mv = &mverts[i]; + float *no = tnorms[i]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); + } + +cleanup: + MEM_freeN(tnorms); + + if (fnors != r_tri_nors) { + MEM_freeN(fnors); + } +} + +void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, + const int numLoops, + const char data_type) +{ + if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) { + MemArena *mem; + + if (!lnors_spacearr->mem) { + lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + mem = lnors_spacearr->mem; + lnors_spacearr->lspacearr = (MLoopNorSpace **)BLI_memarena_calloc( + mem, sizeof(MLoopNorSpace *) * (size_t)numLoops); + lnors_spacearr->loops_pool = (LinkNode *)BLI_memarena_alloc( + mem, sizeof(LinkNode) * (size_t)numLoops); + + lnors_spacearr->num_spaces = 0; + } + BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); + lnors_spacearr->data_type = data_type; +} + +/** + * Utility for multi-threaded calculation that ensures + * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr` + * that would cause it not to be thread safe. + * + * \note This works as long as threads never operate on the same loops at once. + */ +void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls) +{ + *lnors_spacearr_tls = *lnors_spacearr; + lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); +} + +/** + * Utility for multi-threaded calculation + * that merges `lnors_spacearr_tls` into `lnors_spacearr`. + */ +void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpaceArray *lnors_spacearr_tls) +{ + BLI_assert(lnors_spacearr->data_type == lnors_spacearr_tls->data_type); + BLI_assert(lnors_spacearr->mem != lnors_spacearr_tls->mem); + lnors_spacearr->num_spaces += lnors_spacearr_tls->num_spaces; + BLI_memarena_merge(lnors_spacearr->mem, lnors_spacearr_tls->mem); + BLI_memarena_free(lnors_spacearr_tls->mem); + lnors_spacearr_tls->mem = nullptr; + BKE_lnor_spacearr_clear(lnors_spacearr_tls); +} + +void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) +{ + lnors_spacearr->num_spaces = 0; + lnors_spacearr->lspacearr = nullptr; + lnors_spacearr->loops_pool = nullptr; + if (lnors_spacearr->mem != nullptr) { + BLI_memarena_clear(lnors_spacearr->mem); + } +} + +void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) +{ + lnors_spacearr->num_spaces = 0; + lnors_spacearr->lspacearr = nullptr; + lnors_spacearr->loops_pool = nullptr; + BLI_memarena_free(lnors_spacearr->mem); + lnors_spacearr->mem = nullptr; +} + +MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) +{ + lnors_spacearr->num_spaces++; + return (MLoopNorSpace *)BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace)); +} + +/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */ +#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) + +/* Should only be called once. + * Beware, this modifies ref_vec and other_vec in place! + * In case no valid space can be generated, ref_alpha and ref_beta are set to zero + * (which means 'use auto lnors'). + */ +void BKE_lnor_space_define(MLoopNorSpace *lnor_space, + const float lnor[3], + float vec_ref[3], + float vec_other[3], + BLI_Stack *edge_vectors) +{ + const float pi2 = (float)M_PI * 2.0f; + float tvec[3], dtp; + const float dtp_ref = dot_v3v3(vec_ref, lnor); + const float dtp_other = dot_v3v3(vec_other, lnor); + + if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD || + fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) { + /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, + * tag it as invalid and abort. */ + lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; + + if (edge_vectors) { + BLI_stack_clear(edge_vectors); + } + return; + } + + copy_v3_v3(lnor_space->vec_lnor, lnor); + + /* Compute ref alpha, average angle of all available edge vectors to lnor. */ + if (edge_vectors) { + float alpha = 0.0f; + int nbr = 0; + while (!BLI_stack_is_empty(edge_vectors)) { + const float *vec = (const float *)BLI_stack_peek(edge_vectors); + alpha += saacosf(dot_v3v3(vec, lnor)); + BLI_stack_discard(edge_vectors); + nbr++; + } + /* NOTE: In theory, this could be 'nbr > 2', + * but there is one case where we only have two edges for two loops: + * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). + */ + BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */ + lnor_space->ref_alpha = alpha / (float)nbr; + } + else { + lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + + saacosf(dot_v3v3(vec_other, lnor))) / + 2.0f; + } + + /* Project vec_ref on lnor's ortho plane. */ + mul_v3_v3fl(tvec, lnor, dtp_ref); + sub_v3_v3(vec_ref, tvec); + normalize_v3_v3(lnor_space->vec_ref, vec_ref); + + cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref); + normalize_v3_v3(lnor_space->vec_ortho, tvec); + + /* Project vec_other on lnor's ortho plane. */ + mul_v3_v3fl(tvec, lnor, dtp_other); + sub_v3_v3(vec_other, tvec); + normalize_v3(vec_other); + + /* Beta is angle between ref_vec and other_vec, around lnor. */ + dtp = dot_v3v3(lnor_space->vec_ref, vec_other); + if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) { + const float beta = saacos(dtp); + lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; + } + else { + lnor_space->ref_beta = pi2; + } +} + +/** + * Add a new given loop to given lnor_space. + * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct + * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in + * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a + * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the + * linked list of loops in the fan. + */ +void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, + MLoopNorSpace *lnor_space, + const int ml_index, + void *bm_loop, + const bool is_single) +{ + BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == nullptr) || + (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != nullptr)); + + lnors_spacearr->lspacearr[ml_index] = lnor_space; + if (bm_loop == nullptr) { + bm_loop = POINTER_FROM_INT(ml_index); + } + if (is_single) { + BLI_assert(lnor_space->loops == nullptr); + lnor_space->flags |= MLNOR_SPACE_IS_SINGLE; + lnor_space->loops = (LinkNode *)bm_loop; + } + else { + BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0); + BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]); + } +} + +MINLINE float unit_short_to_float(const short val) +{ + return (float)val / (float)SHRT_MAX; +} + +MINLINE short unit_float_to_short(const float val) +{ + /* Rounding... */ + return (short)floorf(val * (float)SHRT_MAX + 0.5f); +} + +void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, + const short clnor_data[2], + float r_custom_lnor[3]) +{ + /* NOP custom normal data or invalid lnor space, return. */ + if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { + copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor); + return; + } + + { + /* TODO: Check whether using #sincosf() gives any noticeable benefit + * (could not even get it working under linux though)! */ + const float pi2 = (float)(M_PI * 2.0); + const float alphafac = unit_short_to_float(clnor_data[0]); + const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * + alphafac; + const float betafac = unit_short_to_float(clnor_data[1]); + + mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha)); + + if (betafac == 0.0f) { + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); + } + else { + const float sinalpha = sinf(alpha); + const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * + betafac; + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); + } + } +} + +void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, + const float custom_lnor[3], + short r_clnor_data[2]) +{ + /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). + */ + if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) { + r_clnor_data[0] = r_clnor_data[1] = 0; + return; + } + + { + const float pi2 = (float)(M_PI * 2.0); + const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor); + float vec[3], cos_beta; + float alpha; + + alpha = saacosf(cos_alpha); + if (alpha > lnor_space->ref_alpha) { + /* Note we could stick to [0, pi] range here, + * but makes decoding more complex, not worth it. */ + r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); + } + else { + r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); + } + + /* Project custom lnor on (vec_ref, vec_ortho) plane. */ + mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha); + add_v3_v3(vec, custom_lnor); + normalize_v3(vec); + + cos_beta = dot_v3v3(lnor_space->vec_ref, vec); + + if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { + float beta = saacosf(cos_beta); + if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { + beta = pi2 - beta; + } + + if (beta > lnor_space->ref_beta) { + r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); + } + else { + r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); + } + } + else { + r_clnor_data[1] = 0; + } + } +} + +#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024 + +struct LoopSplitTaskData { + /* Specific to each instance (each task). */ + + /** We have to create those outside of tasks, since #MemArena is not thread-safe. */ + MLoopNorSpace *lnor_space; + float (*lnor)[3]; + const MLoop *ml_curr; + const MLoop *ml_prev; + int ml_curr_index; + int ml_prev_index; + /** Also used a flag to switch between single or fan process! */ + const int *e2l_prev; + int mp_index; + + /** This one is special, it's owned and managed by worker tasks, + * avoid to have to create it for each fan! */ + BLI_Stack *edge_vectors; + + char pad_c; +}; + +struct LoopSplitTaskDataCommon { + /* Read/write. + * Note we do not need to protect it, though, since two different tasks will *always* affect + * different elements in the arrays. */ + MLoopNorSpaceArray *lnors_spacearr; + float (*loopnors)[3]; + short (*clnors_data)[2]; + + /* Read-only. */ + const MVert *mverts; + const MEdge *medges; + const MLoop *mloops; + const MPoly *mpolys; + int (*edge_to_loops)[2]; + int *loop_to_poly; + const float (*polynors)[3]; + + int numEdges; + int numLoops; + int numPolys; +}; + +#define INDEX_UNSET INT_MIN +#define INDEX_INVALID -1 +/* See comment about edge_to_loops below. */ +#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)) + +static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, + const bool check_angle, + const float split_angle, + const bool do_sharp_edges_tag) +{ + const MVert *mverts = data->mverts; + const MEdge *medges = data->medges; + const MLoop *mloops = data->mloops; + + const MPoly *mpolys = data->mpolys; + + const int numEdges = data->numEdges; + const int numPolys = data->numPolys; + + float(*loopnors)[3] = data->loopnors; /* NOTE: loopnors may be nullptr here. */ + const float(*polynors)[3] = data->polynors; + + int(*edge_to_loops)[2] = data->edge_to_loops; + int *loop_to_poly = data->loop_to_poly; + + BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : nullptr; + + const MPoly *mp; + int mp_index; + + const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; + + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + const MLoop *ml_curr; + int *e2l; + int ml_curr_index = mp->loopstart; + const int ml_last_index = (ml_curr_index + mp->totloop) - 1; + + ml_curr = &mloops[ml_curr_index]; + + for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { + e2l = edge_to_loops[ml_curr->e]; + + loop_to_poly[ml_curr_index] = mp_index; + + /* Pre-populate all loop normals as if their verts were all-smooth, + * this way we don't have to compute those later! + */ + if (loopnors) { + normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no); + } + + /* Check whether current edge might be smooth or sharp */ + if ((e2l[0] | e2l[1]) == 0) { + /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ + e2l[0] = ml_curr_index; + /* We have to check this here too, else we might miss some flat faces!!! */ + e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; + } + else if (e2l[1] == INDEX_UNSET) { + const bool is_angle_sharp = (check_angle && + dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < + split_angle_cos); + + /* Second loop using this edge, time to test its sharpness. + * An edge is sharp if it is tagged as such, or its face is not smooth, + * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the + * same vertex, or angle between both its polys' normals is above split_angle value. + */ + if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || + ml_curr->v == mloops[e2l[0]].v || is_angle_sharp) { + /* NOTE: we are sure that loop != 0 here ;). */ + e2l[1] = INDEX_INVALID; + + /* We want to avoid tagging edges as sharp when it is already defined as such by + * other causes than angle threshold... */ + if (do_sharp_edges_tag && is_angle_sharp) { + BLI_BITMAP_SET(sharp_edges, ml_curr->e, true); + } + } + else { + e2l[1] = ml_curr_index; + } + } + else if (!IS_EDGE_SHARP(e2l)) { + /* More than two loops using this edge, tag as sharp if not yet done. */ + e2l[1] = INDEX_INVALID; + + /* We want to avoid tagging edges as sharp when it is already defined as such by + * other causes than angle threshold... */ + if (do_sharp_edges_tag) { + BLI_BITMAP_SET(sharp_edges, ml_curr->e, false); + } + } + /* Else, edge is already 'disqualified' (i.e. sharp)! */ + } + } + + /* If requested, do actual tagging of edges as sharp in another loop. */ + if (do_sharp_edges_tag) { + MEdge *me; + int me_index; + for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) { + if (BLI_BITMAP_TEST(sharp_edges, me_index)) { + me->flag |= ME_SHARP; + } + } + + MEM_freeN(sharp_edges); + } +} + +/** + * Define sharp edges as needed to mimic 'autosmooth' from angle threshold. + * + * Used when defining an empty custom loop normals data layer, + * to keep same shading as with auto-smooth! + */ +void BKE_edges_sharp_from_angle_set(const struct MVert *mverts, + const int UNUSED(numVerts), + struct MEdge *medges, + const int numEdges, + struct MLoop *mloops, + const int numLoops, + struct MPoly *mpolys, + const float (*polynors)[3], + const int numPolys, + const float split_angle) +{ + if (split_angle >= (float)M_PI) { + /* Nothing to do! */ + return; + } + + /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */ + int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN( + (size_t)numEdges, sizeof(*edge_to_loops), __func__); + + /* Simple mapping from a loop to its polygon index. */ + int *loop_to_poly = (int *)MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + + LoopSplitTaskDataCommon common_data = {}; + common_data.mverts = mverts; + common_data.medges = medges; + common_data.mloops = mloops; + common_data.mpolys = mpolys; + common_data.edge_to_loops = edge_to_loops; + common_data.loop_to_poly = loop_to_poly; + common_data.polynors = polynors; + common_data.numEdges = numEdges; + common_data.numPolys = numPolys; + + mesh_edges_sharp_tag(&common_data, true, split_angle, true); + + MEM_freeN(edge_to_loops); + MEM_freeN(loop_to_poly); +} + +void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, + const MPoly *mpolys, + const int *loop_to_poly, + const int *e2lfan_curr, + const uint mv_pivot_index, + const MLoop **r_mlfan_curr, + int *r_mlfan_curr_index, + int *r_mlfan_vert_index, + int *r_mpfan_curr_index) +{ + const MLoop *mlfan_next; + const MPoly *mpfan_next; + + /* Warning! This is rather complex! + * We have to find our next edge around the vertex (fan mode). + * First we find the next loop, which is either previous or next to mlfan_curr_index, depending + * whether both loops using current edge are in the same direction or not, and whether + * mlfan_curr_index actually uses the vertex we are fanning around! + * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one + * (i.e. not the future mlfan_curr)... + */ + *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0]; + *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index]; + + BLI_assert(*r_mlfan_curr_index >= 0); + BLI_assert(*r_mpfan_curr_index >= 0); + + mlfan_next = &mloops[*r_mlfan_curr_index]; + mpfan_next = &mpolys[*r_mpfan_curr_index]; + if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) || + ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index)) { + /* We need the previous loop, but current one is our vertex's loop. */ + *r_mlfan_vert_index = *r_mlfan_curr_index; + if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) { + *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1; + } + } + else { + /* We need the next loop, which is also our vertex's loop. */ + if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) { + *r_mlfan_curr_index = mpfan_next->loopstart; + } + *r_mlfan_vert_index = *r_mlfan_curr_index; + } + *r_mlfan_curr = &mloops[*r_mlfan_curr_index]; + /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */ +} + +static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) +{ + MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; + const short(*clnors_data)[2] = common_data->clnors_data; + + const MVert *mverts = common_data->mverts; + const MEdge *medges = common_data->medges; + const float(*polynors)[3] = common_data->polynors; + + MLoopNorSpace *lnor_space = data->lnor_space; + float(*lnor)[3] = data->lnor; + const MLoop *ml_curr = data->ml_curr; + const MLoop *ml_prev = data->ml_prev; + const int ml_curr_index = data->ml_curr_index; +#if 0 /* Not needed for 'single' loop. */ + const int ml_prev_index = data->ml_prev_index; + const int *e2l_prev = data->e2l_prev; +#endif + const int mp_index = data->mp_index; + + /* Simple case (both edges around that vertex are sharp in current polygon), + * this loop just takes its poly normal. + */ + copy_v3_v3(*lnor, polynors[mp_index]); + +#if 0 + printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", + ml_curr_index, + ml_curr->e, + ml_curr->v, + mp_index); +#endif + + /* If needed, generate this (simple!) lnor space. */ + if (lnors_spacearr) { + float vec_curr[3], vec_prev[3]; + + const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ + const MVert *mv_pivot = &mverts[mv_pivot_index]; + const MEdge *me_curr = &medges[ml_curr->e]; + const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : + &mverts[me_curr->v1]; + const MEdge *me_prev = &medges[ml_prev->e]; + const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : + &mverts[me_prev->v1]; + + sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); + normalize_v3(vec_curr); + sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co); + normalize_v3(vec_prev); + + BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, nullptr); + /* We know there is only one loop in this space, + * no need to create a linklist in this case... */ + BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true); + + if (clnors_data) { + BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor); + } + } +} + +static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) +{ + MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; + float(*loopnors)[3] = common_data->loopnors; + short(*clnors_data)[2] = common_data->clnors_data; + + const MVert *mverts = common_data->mverts; + const MEdge *medges = common_data->medges; + const MLoop *mloops = common_data->mloops; + const MPoly *mpolys = common_data->mpolys; + const int(*edge_to_loops)[2] = common_data->edge_to_loops; + const int *loop_to_poly = common_data->loop_to_poly; + const float(*polynors)[3] = common_data->polynors; + + MLoopNorSpace *lnor_space = data->lnor_space; +#if 0 /* Not needed for 'fan' loops. */ + float(*lnor)[3] = data->lnor; +#endif + const MLoop *ml_curr = data->ml_curr; + const MLoop *ml_prev = data->ml_prev; + const int ml_curr_index = data->ml_curr_index; + const int ml_prev_index = data->ml_prev_index; + const int mp_index = data->mp_index; + const int *e2l_prev = data->e2l_prev; + + BLI_Stack *edge_vectors = data->edge_vectors; + + /* Gah... We have to fan around current vertex, until we find the other non-smooth edge, + * and accumulate face normals into the vertex! + * Note in case this vertex has only one sharp edges, this is a waste because the normal is the + * same as the vertex normal, but I do not see any easy way to detect that (would need to count + * number of sharp edges per vertex, I doubt the additional memory usage would be worth it, + * especially as it should not be a common case in real-life meshes anyway). + */ + const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ + const MVert *mv_pivot = &mverts[mv_pivot_index]; + + /* ml_curr would be mlfan_prev if we needed that one. */ + const MEdge *me_org = &medges[ml_curr->e]; + + const int *e2lfan_curr; + float vec_curr[3], vec_prev[3], vec_org[3]; + const MLoop *mlfan_curr; + float lnor[3] = {0.0f, 0.0f, 0.0f}; + /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ + int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; + + /* We validate clnors data on the fly - cheapest way to do! */ + int clnors_avg[2] = {0, 0}; + short(*clnor_ref)[2] = nullptr; + int clnors_nbr = 0; + bool clnors_invalid = false; + + /* Temp loop normal stack. */ + BLI_SMALLSTACK_DECLARE(normal, float *); + /* Temp clnors stack. */ + BLI_SMALLSTACK_DECLARE(clnors, short *); + + e2lfan_curr = e2l_prev; + mlfan_curr = ml_prev; + mlfan_curr_index = ml_prev_index; + mlfan_vert_index = ml_curr_index; + mpfan_curr_index = mp_index; + + BLI_assert(mlfan_curr_index >= 0); + BLI_assert(mlfan_vert_index >= 0); + BLI_assert(mpfan_curr_index >= 0); + + /* Only need to compute previous edge's vector once, then we can just reuse old current one! */ + { + const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1]; + + sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co); + normalize_v3(vec_org); + copy_v3_v3(vec_prev, vec_org); + + if (lnors_spacearr) { + BLI_stack_push(edge_vectors, vec_org); + } + } + + // printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); + + while (true) { + const MEdge *me_curr = &medges[mlfan_curr->e]; + /* Compute edge vectors. + * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing + * them twice (or more) here. However, time gained is not worth memory and time lost, + * given the fact that this code should not be called that much in real-life meshes... + */ + { + const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : + &mverts[me_curr->v1]; + + sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); + normalize_v3(vec_curr); + } + + // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); + + { + /* Code similar to accumulate_vertex_normals_poly_v3. */ + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(dot_v3v3(vec_curr, vec_prev)); + /* Accumulate */ + madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); + + if (clnors_data) { + /* Accumulate all clnors, if they are not all equal we have to fix that! */ + short(*clnor)[2] = &clnors_data[mlfan_vert_index]; + if (clnors_nbr) { + clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); + } + else { + clnor_ref = clnor; + } + clnors_avg[0] += (*clnor)[0]; + clnors_avg[1] += (*clnor)[1]; + clnors_nbr++; + /* We store here a pointer to all custom lnors processed. */ + BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor); + } + } + + /* We store here a pointer to all loop-normals processed. */ + BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index])); + + if (lnors_spacearr) { + /* Assign current lnor space to current 'vertex' loop. */ + BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, nullptr, false); + if (me_curr != me_org) { + /* We store here all edges-normalized vectors processed. */ + BLI_stack_push(edge_vectors, vec_curr); + } + } + + if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) { + /* Current edge is sharp and we have finished with this fan of faces around this vert, + * or this vert is smooth, and we have completed a full turn around it. */ + // printf("FAN: Finished!\n"); + break; + } + + copy_v3_v3(vec_prev, vec_curr); + + /* Find next loop of the smooth fan. */ + BKE_mesh_loop_manifold_fan_around_vert_next(mloops, + mpolys, + loop_to_poly, + e2lfan_curr, + mv_pivot_index, + &mlfan_curr, + &mlfan_curr_index, + &mlfan_vert_index, + &mpfan_curr_index); + + e2lfan_curr = edge_to_loops[mlfan_curr->e]; + } + + { + float lnor_len = normalize_v3(lnor); + + /* If we are generating lnor spacearr, we can now define the one for this fan, + * and optionally compute final lnor from custom data too! + */ + if (lnors_spacearr) { + if (UNLIKELY(lnor_len == 0.0f)) { + /* Use vertex normal as fallback! */ + copy_v3_v3(lnor, loopnors[mlfan_vert_index]); + lnor_len = 1.0f; + } + + BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors); + + if (clnors_data) { + if (clnors_invalid) { + short *clnor; + + clnors_avg[0] /= clnors_nbr; + clnors_avg[1] /= clnors_nbr; + /* Fix/update all clnors of this fan with computed average value. */ + if (G.debug & G_DEBUG) { + printf("Invalid clnors in this fan!\n"); + } + while ((clnor = (short *)BLI_SMALLSTACK_POP(clnors))) { + // print_v2("org clnor", clnor); + clnor[0] = (short)clnors_avg[0]; + clnor[1] = (short)clnors_avg[1]; + } + // print_v2("new clnors", clnors_avg); + } + /* Extra bonus: since small-stack is local to this function, + * no more need to empty it at all cost! */ + + BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); + } + } + + /* In case we get a zero normal here, just use vertex normal already set! */ + if (LIKELY(lnor_len != 0.0f)) { + /* Copy back the final computed normal into all related loop-normals. */ + float *nor; + + while ((nor = (float *)BLI_SMALLSTACK_POP(normal))) { + copy_v3_v3(nor, lnor); + } + } + /* Extra bonus: since small-stack is local to this function, + * no more need to empty it at all cost! */ + } +} + +static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data, + LoopSplitTaskData *data, + BLI_Stack *edge_vectors) +{ + BLI_assert(data->ml_curr); + if (data->e2l_prev) { + BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors)); + data->edge_vectors = edge_vectors; + split_loop_nor_fan_do(common_data, data); + } + else { + /* No need for edge_vectors for 'single' case! */ + split_loop_nor_single_do(common_data, data); + } +} + +static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) +{ + LoopSplitTaskDataCommon *common_data = (LoopSplitTaskDataCommon *)BLI_task_pool_user_data(pool); + LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata; + + /* Temp edge vectors stack, only used when computing lnor spacearr. */ + BLI_Stack *edge_vectors = common_data->lnors_spacearr ? + BLI_stack_new(sizeof(float[3]), __func__) : + nullptr; + +#ifdef DEBUG_TIME + TIMEIT_START_AVERAGED(loop_split_worker); +#endif + + for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) { + /* A nullptr ml_curr is used to tag ended data! */ + if (data->ml_curr == nullptr) { + break; + } + + loop_split_worker_do(common_data, data, edge_vectors); + } + + if (edge_vectors) { + BLI_stack_free(edge_vectors); + } + +#ifdef DEBUG_TIME + TIMEIT_END_AVERAGED(loop_split_worker); +#endif +} + +/** + * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not. + * Needed because cyclic smooth fans have no obvious 'entry point', + * and yet we need to walk them once, and only once. + */ +static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, + const MPoly *mpolys, + const int (*edge_to_loops)[2], + const int *loop_to_poly, + const int *e2l_prev, + BLI_bitmap *skip_loops, + const MLoop *ml_curr, + const MLoop *ml_prev, + const int ml_curr_index, + const int ml_prev_index, + const int mp_curr_index) +{ + const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ + const int *e2lfan_curr; + const MLoop *mlfan_curr; + /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ + int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; + + e2lfan_curr = e2l_prev; + if (IS_EDGE_SHARP(e2lfan_curr)) { + /* Sharp loop, so not a cyclic smooth fan... */ + return false; + } + + mlfan_curr = ml_prev; + mlfan_curr_index = ml_prev_index; + mlfan_vert_index = ml_curr_index; + mpfan_curr_index = mp_curr_index; + + BLI_assert(mlfan_curr_index >= 0); + BLI_assert(mlfan_vert_index >= 0); + BLI_assert(mpfan_curr_index >= 0); + + BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)); + BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index); + + while (true) { + /* Find next loop of the smooth fan. */ + BKE_mesh_loop_manifold_fan_around_vert_next(mloops, + mpolys, + loop_to_poly, + e2lfan_curr, + mv_pivot_index, + &mlfan_curr, + &mlfan_curr_index, + &mlfan_vert_index, + &mpfan_curr_index); + + e2lfan_curr = edge_to_loops[mlfan_curr->e]; + + if (IS_EDGE_SHARP(e2lfan_curr)) { + /* Sharp loop/edge, so not a cyclic smooth fan... */ + return false; + } + /* Smooth loop/edge... */ + if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) { + if (mlfan_vert_index == ml_curr_index) { + /* We walked around a whole cyclic smooth fan without finding any already-processed loop, + * means we can use initial ml_curr/ml_prev edge as start for this smooth fan. */ + return true; + } + /* ... already checked in some previous looping, we can abort. */ + return false; + } + + /* ... we can skip it in future, and keep checking the smooth fan. */ + BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index); + } +} + +static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data) +{ + MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; + float(*loopnors)[3] = common_data->loopnors; + + const MLoop *mloops = common_data->mloops; + const MPoly *mpolys = common_data->mpolys; + const int *loop_to_poly = common_data->loop_to_poly; + const int(*edge_to_loops)[2] = common_data->edge_to_loops; + const int numLoops = common_data->numLoops; + const int numPolys = common_data->numPolys; + + const MPoly *mp; + int mp_index; + + const MLoop *ml_curr; + const MLoop *ml_prev; + int ml_curr_index; + int ml_prev_index; + + BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__); + + LoopSplitTaskData *data_buff = nullptr; + int data_idx = 0; + + /* Temp edge vectors stack, only used when computing lnor spacearr + * (and we are not multi-threading). */ + BLI_Stack *edge_vectors = nullptr; + +#ifdef DEBUG_TIME + TIMEIT_START_AVERAGED(loop_split_generator); +#endif + + if (!pool) { + if (lnors_spacearr) { + edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); + } + } + + /* We now know edges that can be smoothed (with their vector, and their two loops), + * and edges that will be hard! Now, time to generate the normals. + */ + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + float(*lnors)[3]; + const int ml_last_index = (mp->loopstart + mp->totloop) - 1; + ml_curr_index = mp->loopstart; + ml_prev_index = ml_last_index; + + ml_curr = &mloops[ml_curr_index]; + ml_prev = &mloops[ml_prev_index]; + lnors = &loopnors[ml_curr_index]; + + for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) { + const int *e2l_curr = edge_to_loops[ml_curr->e]; + const int *e2l_prev = edge_to_loops[ml_prev->e]; + +#if 0 + printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...", + ml_curr_index, + ml_curr->e, + ml_curr->v, + IS_EDGE_SHARP(e2l_curr), + BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index)); +#endif + + /* A smooth edge, we have to check for cyclic smooth fan case. + * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge + * as 'entry point', otherwise we can skip it. */ + + /* NOTE: In theory, we could make #loop_split_generator_check_cyclic_smooth_fan() store + * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around + * the vert during actual computation of `clnor` & `clnorspace`. + * However, this would complicate the code, add more memory usage, and despite its logical + * complexity, #loop_manifold_fan_around_vert_next() is quite cheap in term of CPU cycles, + * so really think it's not worth it. */ + if (!IS_EDGE_SHARP(e2l_curr) && (BLI_BITMAP_TEST(skip_loops, ml_curr_index) || + !loop_split_generator_check_cyclic_smooth_fan(mloops, + mpolys, + edge_to_loops, + loop_to_poly, + e2l_prev, + skip_loops, + ml_curr, + ml_prev, + ml_curr_index, + ml_prev_index, + mp_index))) { + // printf("SKIPPING!\n"); + } + else { + LoopSplitTaskData *data, data_local; + + // printf("PROCESSING!\n"); + + if (pool) { + if (data_idx == 0) { + data_buff = (LoopSplitTaskData *)MEM_calloc_arrayN( + LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__); + } + data = &data_buff[data_idx]; + } + else { + data = &data_local; + memset(data, 0, sizeof(*data)); + } + + if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) { + data->lnor = lnors; + data->ml_curr = ml_curr; + data->ml_prev = ml_prev; + data->ml_curr_index = ml_curr_index; +#if 0 /* Not needed for 'single' loop. */ + data->ml_prev_index = ml_prev_index; + data->e2l_prev = nullptr; /* Tag as 'single' task. */ +#endif + data->mp_index = mp_index; + if (lnors_spacearr) { + data->lnor_space = BKE_lnor_space_create(lnors_spacearr); + } + } + /* We *do not need* to check/tag loops as already computed! + * Due to the fact a loop only links to one of its two edges, + * a same fan *will never be walked more than once!* + * Since we consider edges having neighbor polys with inverted + * (flipped) normals as sharp, we are sure that no fan will be skipped, + * even only considering the case (sharp curr_edge, smooth prev_edge), + * and not the alternative (smooth curr_edge, sharp prev_edge). + * All this due/thanks to link between normals and loop ordering (i.e. winding). + */ + else { +#if 0 /* Not needed for 'fan' loops. */ + data->lnor = lnors; +#endif + data->ml_curr = ml_curr; + data->ml_prev = ml_prev; + data->ml_curr_index = ml_curr_index; + data->ml_prev_index = ml_prev_index; + data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */ + data->mp_index = mp_index; + if (lnors_spacearr) { + data->lnor_space = BKE_lnor_space_create(lnors_spacearr); + } + } + + if (pool) { + data_idx++; + if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) { + BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr); + data_idx = 0; + } + } + else { + loop_split_worker_do(common_data, data, edge_vectors); + } + } + + ml_prev = ml_curr; + ml_prev_index = ml_curr_index; + } + } + + /* Last block of data... Since it is calloc'ed and we use first nullptr item as stopper, + * everything is fine. */ + if (pool && data_idx) { + BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr); + } + + if (edge_vectors) { + BLI_stack_free(edge_vectors); + } + MEM_freeN(skip_loops); + +#ifdef DEBUG_TIME + TIMEIT_END_AVERAGED(loop_split_generator); +#endif +} + +/** + * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). + * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry + * (splitting edges). + */ +void BKE_mesh_normals_loop_split(const MVert *mverts, + const int UNUSED(numVerts), + MEdge *medges, + const int numEdges, + MLoop *mloops, + float (*r_loopnors)[3], + const int numLoops, + MPoly *mpolys, + const float (*polynors)[3], + const int numPolys, + const bool use_split_normals, + const float split_angle, + MLoopNorSpaceArray *r_lnors_spacearr, + short (*clnors_data)[2], + int *r_loop_to_poly) +{ + /* For now this is not supported. + * If we do not use split normals, we do not generate anything fancy! */ + BLI_assert(use_split_normals || !(r_lnors_spacearr)); + + if (!use_split_normals) { + /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple! + * Note this is done here to keep some logic and consistency in this quite complex code, + * since we may want to use lnors even when mesh's 'autosmooth' is disabled + * (see e.g. mesh mapping code). + * As usual, we could handle that on case-by-case basis, + * but simpler to keep it well confined here. + */ + int mp_index; + + for (mp_index = 0; mp_index < numPolys; mp_index++) { + MPoly *mp = &mpolys[mp_index]; + int ml_index = mp->loopstart; + const int ml_index_end = ml_index + mp->totloop; + const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0); + + for (; ml_index < ml_index_end; ml_index++) { + if (r_loop_to_poly) { + r_loop_to_poly[ml_index] = mp_index; + } + if (is_poly_flat) { + copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]); + } + else { + normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no); + } + } + } + return; + } + + /** + * Mapping edge -> loops. + * If that edge is used by more than two loops (polys), + * it is always sharp (and tagged as such, see below). + * We also use the second loop index as a kind of flag: + * + * - smooth edge: > 0. + * - sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET). + * - unset: INDEX_UNSET. + * + * Note that currently we only have two values for second loop of sharp edges. + * However, if needed, we can store the negated value of loop index instead of INDEX_INVALID + * to retrieve the real value later in code). + * Note also that loose edges always have both values set to 0! */ + int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN( + (size_t)numEdges, sizeof(*edge_to_loops), __func__); + + /* Simple mapping from a loop to its polygon index. */ + int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : + (int *)MEM_malloc_arrayN( + (size_t)numLoops, sizeof(*loop_to_poly), __func__); + + /* When using custom loop normals, disable the angle feature! */ + const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == nullptr); + + MLoopNorSpaceArray _lnors_spacearr = {nullptr}; + +#ifdef DEBUG_TIME + TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split); +#endif + + if (!r_lnors_spacearr && clnors_data) { + /* We need to compute lnor spacearr if some custom lnor data are given to us! */ + r_lnors_spacearr = &_lnors_spacearr; + } + if (r_lnors_spacearr) { + BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX); + } + + /* Init data common to all tasks. */ + LoopSplitTaskDataCommon common_data; + common_data.lnors_spacearr = r_lnors_spacearr; + common_data.loopnors = r_loopnors; + common_data.clnors_data = clnors_data; + common_data.mverts = mverts; + common_data.medges = medges; + common_data.mloops = mloops; + common_data.mpolys = mpolys; + common_data.edge_to_loops = edge_to_loops; + common_data.loop_to_poly = loop_to_poly; + common_data.polynors = polynors; + common_data.numEdges = numEdges; + common_data.numLoops = numLoops; + common_data.numPolys = numPolys; + + /* This first loop check which edges are actually smooth, and compute edge vectors. */ + mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false); + + if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { + /* Not enough loops to be worth the whole threading overhead... */ + loop_split_generator(nullptr, &common_data); + } + else { + TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH); + + loop_split_generator(task_pool, &common_data); + + BLI_task_pool_work_and_wait(task_pool); + + BLI_task_pool_free(task_pool); + } + + MEM_freeN(edge_to_loops); + if (!r_loop_to_poly) { + MEM_freeN(loop_to_poly); + } + + if (r_lnors_spacearr) { + if (r_lnors_spacearr == &_lnors_spacearr) { + BKE_lnor_spacearr_free(r_lnors_spacearr); + } + } + +#ifdef DEBUG_TIME + TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split); +#endif +} + +#undef INDEX_UNSET +#undef INDEX_INVALID +#undef IS_EDGE_SHARP + +/** + * Compute internal representation of given custom normals (as an array of float[2]). + * It also makes sure the mesh matches those custom normals, by setting sharp edges flag as needed + * to get a same custom lnor for all loops sharing a same smooth fan. + * If use_vertices if true, r_custom_loopnors is assumed to be per-vertex, not per-loop + * (this allows to set whole vert's normals at once, useful in some cases). + * r_custom_loopnors is expected to have normalized normals, or zero ones, + * in which case they will be replaced by default loop/vertex normal. + */ +static void mesh_normals_loop_custom_set(const MVert *mverts, + const int numVerts, + MEdge *medges, + const int numEdges, + MLoop *mloops, + float (*r_custom_loopnors)[3], + const int numLoops, + MPoly *mpolys, + const float (*polynors)[3], + const int numPolys, + short (*r_clnors_data)[2], + const bool use_vertices) +{ + /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling + * that feature too, would probably be more efficient in absolute. + * However, this function *is not* performance-critical, since it is mostly expected to be called + * by io addons when importing custom normals, and modifier + * (and perhaps from some editing tools later?). + * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice! + */ + MLoopNorSpaceArray lnors_spacearr = {nullptr}; + BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__); + float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__); + int *loop_to_poly = (int *)MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__); + /* In this case we always consider split nors as ON, + * and do not want to use angle to define smooth fans! */ + const bool use_split_normals = true; + const float split_angle = (float)M_PI; + + BLI_SMALLSTACK_DECLARE(clnors_data, short *); + + /* Compute current lnor spacearr. */ + BKE_mesh_normals_loop_split(mverts, + numVerts, + medges, + numEdges, + mloops, + lnors, + numLoops, + mpolys, + polynors, + numPolys, + use_split_normals, + split_angle, + &lnors_spacearr, + nullptr, + loop_to_poly); + + /* Set all given zero vectors to their default value. */ + if (use_vertices) { + for (int i = 0; i < numVerts; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no); + } + } + } + else { + for (int i = 0; i < numLoops; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + copy_v3_v3(r_custom_loopnors[i], lnors[i]); + } + } + } + + BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX); + + /* Now, check each current smooth fan (one lnor space per smooth fan!), + * and if all its matching custom lnors are not (enough) equal, add sharp edges as needed. + * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans + * matching given custom lnors. + * Note this code *will never* unsharp edges! And quite obviously, + * when we set custom normals per vertices, running this is absolutely useless. + */ + if (!use_vertices) { + for (int i = 0; i < numLoops; i++) { + if (!lnors_spacearr.lspacearr[i]) { + /* This should not happen in theory, but in some rare case (probably ugly geometry) + * we can get some nullptr loopspacearr at this point. :/ + * Maybe we should set those loops' edges as sharp? + */ + BLI_BITMAP_ENABLE(done_loops, i); + if (G.debug & G_DEBUG) { + printf("WARNING! Getting invalid nullptr loop space for loop %d!\n", i); + } + continue; + } + + if (!BLI_BITMAP_TEST(done_loops, i)) { + /* Notes: + * * In case of mono-loop smooth fan, we have nothing to do. + * * Loops in this linklist are ordered (in reversed order compared to how they were + * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). + * Which means if we find a mismatching clnor, + * we know all remaining loops will have to be in a new, different smooth fan/lnor space. + * * In smooth fan case, we compare each clnor against a ref one, + * to avoid small differences adding up into a real big one in the end! + */ + if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_BITMAP_ENABLE(done_loops, i); + continue; + } + + LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; + MLoop *prev_ml = nullptr; + const float *org_nor = nullptr; + + while (loops) { + const int lidx = POINTER_AS_INT(loops->link); + MLoop *ml = &mloops[lidx]; + const int nidx = lidx; + float *nor = r_custom_loopnors[nidx]; + + if (!org_nor) { + org_nor = nor; + } + else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { + /* Current normal differs too much from org one, we have to tag the edge between + * previous loop's face and current's one as sharp. + * We know those two loops do not point to the same edge, + * since we do not allow reversed winding in a same smooth fan. + */ + const MPoly *mp = &mpolys[loop_to_poly[lidx]]; + const MLoop *mlp = + &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; + medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; + + org_nor = nor; + } + + prev_ml = ml; + loops = loops->next; + BLI_BITMAP_ENABLE(done_loops, lidx); + } + + /* We also have to check between last and first loops, + * otherwise we may miss some sharp edges here! + * This is just a simplified version of above while loop. + * See T45984. */ + loops = lnors_spacearr.lspacearr[i]->loops; + if (loops && org_nor) { + const int lidx = POINTER_AS_INT(loops->link); + MLoop *ml = &mloops[lidx]; + const int nidx = lidx; + float *nor = r_custom_loopnors[nidx]; + + if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { + const MPoly *mp = &mpolys[loop_to_poly[lidx]]; + const MLoop *mlp = + &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; + medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; + } + } + } + } + + /* And now, recompute our new auto lnors and lnor spacearr! */ + BKE_lnor_spacearr_clear(&lnors_spacearr); + BKE_mesh_normals_loop_split(mverts, + numVerts, + medges, + numEdges, + mloops, + lnors, + numLoops, + mpolys, + polynors, + numPolys, + use_split_normals, + split_angle, + &lnors_spacearr, + nullptr, + loop_to_poly); + } + else { + BLI_bitmap_set_all(done_loops, true, (size_t)numLoops); + } + + /* And we just have to convert plain object-space custom normals to our + * lnor space-encoded ones. */ + for (int i = 0; i < numLoops; i++) { + if (!lnors_spacearr.lspacearr[i]) { + BLI_BITMAP_DISABLE(done_loops, i); + if (G.debug & G_DEBUG) { + printf("WARNING! Still getting invalid nullptr loop space in second loop for loop %d!\n", + i); + } + continue; + } + + if (BLI_BITMAP_TEST_BOOL(done_loops, i)) { + /* Note we accumulate and average all custom normals in current smooth fan, + * to avoid getting different clnors data (tiny differences in plain custom normals can + * give rather huge differences in computed 2D factors). + */ + LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; + if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_assert(POINTER_AS_INT(loops) == i); + const int nidx = use_vertices ? (int)mloops[i].v : i; + float *nor = r_custom_loopnors[nidx]; + + BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); + BLI_BITMAP_DISABLE(done_loops, i); + } + else { + int nbr_nors = 0; + float avg_nor[3]; + short clnor_data_tmp[2], *clnor_data; + + zero_v3(avg_nor); + while (loops) { + const int lidx = POINTER_AS_INT(loops->link); + const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; + float *nor = r_custom_loopnors[nidx]; + + nbr_nors++; + add_v3_v3(avg_nor, nor); + BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]); + + loops = loops->next; + BLI_BITMAP_DISABLE(done_loops, lidx); + } + + mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors); + BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp); + + while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) { + clnor_data[0] = clnor_data_tmp[0]; + clnor_data[1] = clnor_data_tmp[1]; + } + } + } + } + + MEM_freeN(lnors); + MEM_freeN(loop_to_poly); + MEM_freeN(done_loops); + BKE_lnor_spacearr_free(&lnors_spacearr); +} + +void BKE_mesh_normals_loop_custom_set(const MVert *mverts, + const int numVerts, + MEdge *medges, + const int numEdges, + MLoop *mloops, + float (*r_custom_loopnors)[3], + const int numLoops, + MPoly *mpolys, + const float (*polynors)[3], + const int numPolys, + short (*r_clnors_data)[2]) +{ + mesh_normals_loop_custom_set(mverts, + numVerts, + medges, + numEdges, + mloops, + r_custom_loopnors, + numLoops, + mpolys, + polynors, + numPolys, + r_clnors_data, + false); +} + +void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts, + float (*r_custom_vertnors)[3], + const int numVerts, + MEdge *medges, + const int numEdges, + MLoop *mloops, + const int numLoops, + MPoly *mpolys, + const float (*polynors)[3], + const int numPolys, + short (*r_clnors_data)[2]) +{ + mesh_normals_loop_custom_set(mverts, + numVerts, + medges, + numEdges, + mloops, + r_custom_vertnors, + numLoops, + mpolys, + polynors, + numPolys, + r_clnors_data, + true); +} + +static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices) +{ + short(*clnors)[2]; + const int numloops = mesh->totloop; + + clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + if (clnors != nullptr) { + memset(clnors, 0, sizeof(*clnors) * (size_t)numloops); + } + else { + clnors = (short(*)[2])CustomData_add_layer( + &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops); + } + + float(*polynors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); + bool free_polynors = false; + if (polynors == nullptr) { + polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__); + BKE_mesh_calc_normals_poly(mesh->mvert, + nullptr, + mesh->totvert, + mesh->mloop, + mesh->mpoly, + mesh->totloop, + mesh->totpoly, + polynors, + false); + free_polynors = true; + } + + mesh_normals_loop_custom_set(mesh->mvert, + mesh->totvert, + mesh->medge, + mesh->totedge, + mesh->mloop, + r_custom_nors, + mesh->totloop, + mesh->mpoly, + polynors, + mesh->totpoly, + clnors, + use_vertices); + + if (free_polynors) { + MEM_freeN(polynors); + } +} + +/** + * Higher level functions hiding most of the code needed around call to + * #BKE_mesh_normals_loop_custom_set(). + * + * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there + * with automatically computed vectors. + */ +void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3]) +{ + mesh_set_custom_normals(mesh, r_custom_loopnors, false); +} + +/** + * Higher level functions hiding most of the code needed around call to + * #BKE_mesh_normals_loop_custom_from_vertices_set(). + * + * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there + * with automatically computed vectors. + */ +void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3]) +{ + mesh_set_custom_normals(mesh, r_custom_vertnors, true); +} + +/** + * Computes average per-vertex normals from given custom loop normals. + * + * \param clnors: The computed custom loop normals. + * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals. + */ +void BKE_mesh_normals_loop_to_vertex(const int numVerts, + const MLoop *mloops, + const int numLoops, + const float (*clnors)[3], + float (*r_vert_clnors)[3]) +{ + int *vert_loops_nbr = (int *)MEM_calloc_arrayN( + (size_t)numVerts, sizeof(*vert_loops_nbr), __func__); + + copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f); + + int i; + const MLoop *ml; + for (i = 0, ml = mloops; i < numLoops; i++, ml++) { + const uint v = ml->v; + + add_v3_v3(r_vert_clnors[v], clnors[i]); + vert_loops_nbr[v]++; + } + + for (i = 0; i < numVerts; i++) { + mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]); + } + + MEM_freeN(vert_loops_nbr); +} + +#undef LNOR_SPACE_TRIGO_THRESHOLD + +/** \} */ -- cgit v1.2.3 From c9a9d5332bbe31c5f1c8974eeee3064d02557061 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 11 Aug 2021 11:38:34 -0300 Subject: PyAPI: GPU: Expose builtin shaders Expose `3D_POLYLINE_SMOOTH_COLOR` and `3D_POLYLINE_FLAT_COLOR` builtins. Requested by addon developers. --- source/blender/python/gpu/gpu_py_shader.c | 40 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index b3f1c186716..41c40fdeb96 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -44,14 +44,28 @@ /** \name Enum Conversion. * \{ */ +#define PYDOC_BUILTIN_SHADER_LIST \ + " - ``2D_FLAT_COLOR``\n" \ + " - ``2D_IMAGE``\n" \ + " - ``2D_SMOOTH_COLOR``\n" \ + " - ``2D_UNIFORM_COLOR``\n" \ + " - ``3D_FLAT_COLOR``\n" \ + " - ``3D_SMOOTH_COLOR``\n" \ + " - ``3D_UNIFORM_COLOR``\n" \ + " - ``3D_POLYLINE_FLAT_COLOR``\n" \ + " - ``3D_POLYLINE_SMOOTH_COLOR``\n" \ + " - ``3D_POLYLINE_UNIFORM_COLOR``\n" + static const struct PyC_StringEnumItems pygpu_shader_builtin_items[] = { - {GPU_SHADER_2D_UNIFORM_COLOR, "2D_UNIFORM_COLOR"}, {GPU_SHADER_2D_FLAT_COLOR, "2D_FLAT_COLOR"}, - {GPU_SHADER_2D_SMOOTH_COLOR, "2D_SMOOTH_COLOR"}, {GPU_SHADER_2D_IMAGE, "2D_IMAGE"}, - {GPU_SHADER_3D_UNIFORM_COLOR, "3D_UNIFORM_COLOR"}, + {GPU_SHADER_2D_SMOOTH_COLOR, "2D_SMOOTH_COLOR"}, + {GPU_SHADER_2D_UNIFORM_COLOR, "2D_UNIFORM_COLOR"}, {GPU_SHADER_3D_FLAT_COLOR, "3D_FLAT_COLOR"}, {GPU_SHADER_3D_SMOOTH_COLOR, "3D_SMOOTH_COLOR"}, + {GPU_SHADER_3D_UNIFORM_COLOR, "3D_UNIFORM_COLOR"}, + {GPU_SHADER_3D_POLYLINE_FLAT_COLOR, "3D_POLYLINE_FLAT_COLOR"}, + {GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR, "3D_POLYLINE_SMOOTH_COLOR"}, {GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, "3D_POLYLINE_UNIFORM_COLOR"}, {0, NULL}, }; @@ -704,14 +718,8 @@ PyDoc_STRVAR(pygpu_shader_from_builtin_doc, " For more details, you can check the shader code with the\n" " :func:`gpu.shader.code_from_builtin` function.\n" "\n" - " :param pygpu_shader_name: One of these builtin shader names:\n\n" - " - ``2D_UNIFORM_COLOR``\n" - " - ``2D_FLAT_COLOR``\n" - " - ``2D_SMOOTH_COLOR``\n" - " - ``2D_IMAGE``\n" - " - ``3D_UNIFORM_COLOR``\n" - " - ``3D_FLAT_COLOR``\n" - " - ``3D_SMOOTH_COLOR``\n" + " :param pygpu_shader_name: One of these builtin shader names:\n" + "\n" PYDOC_BUILTIN_SHADER_LIST " :type pygpu_shader_name: str\n" " :return: Shader object corresponding to the given name.\n" " :rtype: :class:`bpy.types.GPUShader`\n"); @@ -734,14 +742,8 @@ PyDoc_STRVAR(pygpu_shader_code_from_builtin_doc, "\n" " Exposes the internal shader code for query.\n" "\n" - " :param pygpu_shader_name: One of these builtin shader names:\n\n" - " - ``2D_UNIFORM_COLOR``\n" - " - ``2D_FLAT_COLOR``\n" - " - ``2D_SMOOTH_COLOR``\n" - " - ``2D_IMAGE``\n" - " - ``3D_UNIFORM_COLOR``\n" - " - ``3D_FLAT_COLOR``\n" - " - ``3D_SMOOTH_COLOR``\n" + " :param pygpu_shader_name: One of these builtin shader names:\n" + "\n" PYDOC_BUILTIN_SHADER_LIST " :type pygpu_shader_name: str\n" " :return: Vertex, fragment and geometry shader codes.\n" " :rtype: dict\n"); -- cgit v1.2.3 From e53afad2414969ac0a1affb11398feff0df00516 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 11 Aug 2021 16:18:52 +0200 Subject: Cleanup: moved keyframe drawing to a draw list. In preparation to do threaded drawing preparation. There should not be any functional changes. --- source/blender/editors/animation/keyframes_draw.c | 289 +++++++++++++++------ source/blender/editors/include/ED_keyframes_draw.h | 26 +- source/blender/editors/space_action/action_draw.c | 25 +- 3 files changed, 247 insertions(+), 93 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index d858ef3ca5a..d25f81005c5 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -25,6 +25,8 @@ #include +#include "MEM_guardedalloc.h" + #include "BLI_dlrbTree.h" #include "BLI_listbase.h" #include "BLI_rect.h" @@ -455,95 +457,232 @@ static void draw_keylist(View2D *v2d, draw_keylist_keys(&ctx, v2d, columns, ypos, saction_flag); } -/* *************************** Channel Drawing Funcs *************************** */ +/* *************************** Drawing Stack *************************** */ +typedef enum eAnimKeylistDrawListElemType { + ANIM_KEYLIST_SUMMARY, + ANIM_KEYLIST_SCENE, + ANIM_KEYLIST_OBJECT, + ANIM_KEYLIST_FCURVE, + ANIM_KEYLIST_ACTION, + ANIM_KEYLIST_AGROUP, + ANIM_KEYLIST_GP_LAYER, + ANIM_KEYLIST_MASK_LAYER, +} eAnimKeylistDrawListElemType; + +typedef struct AnimKeylistDrawListElem { + struct AnimKeylistDrawListElem *next, *prev; + struct AnimKeylist *keylist; + eAnimKeylistDrawListElemType type; + + float yscale_fac; + float ypos; + eSAction_Flag saction_flag; + bool channel_locked; + + bAnimContext *ac; + bDopeSheet *ads; + Scene *sce; + Object *ob; + AnimData *adt; + FCurve *fcu; + bAction *act; + bActionGroup *agrp; + bGPDlayer *gpl; + MaskLayer *masklay; + +} AnimKeylistDrawListElem; + +static void ED_keylist_draw_list_elem_build_keylist(AnimKeylistDrawListElem *elem) +{ + switch (elem->type) { + case ANIM_KEYLIST_SUMMARY: { + summary_to_keylist(elem->ac, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_SCENE: { + scene_to_keylist(elem->ads, elem->sce, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_OBJECT: { + ob_to_keylist(elem->ads, elem->ob, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_FCURVE: { + fcurve_to_keylist(elem->adt, elem->fcu, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_ACTION: { + action_to_keylist(elem->adt, elem->act, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_AGROUP: { + agroup_to_keylist(elem->adt, elem->agrp, elem->keylist, elem->saction_flag); + break; + } + case ANIM_KEYLIST_GP_LAYER: { + gpl_to_keylist(elem->ads, elem->gpl, elem->keylist); + break; + } + case ANIM_KEYLIST_MASK_LAYER: { + mask_to_keylist(elem->ads, elem->masklay, elem->keylist); + break; + } + } +} -void draw_summary_channel( - View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag) +static void ED_keylist_draw_list_elem_draw(AnimKeylistDrawListElem *elem, View2D *v2d) { - struct AnimKeylist *keylist = ED_keylist_create(); + draw_keylist( + v2d, elem->keylist, elem->ypos, elem->yscale_fac, elem->channel_locked, elem->saction_flag); +} - saction_flag &= ~SACTION_SHOW_EXTREMES; +typedef struct AnimKeylistDrawList { + ListBase /* AnimKeylistDrawListElem*/ channels; +} AnimKeylistDrawList; - summary_to_keylist(ac, keylist, saction_flag); +AnimKeylistDrawList *ED_keylist_draw_list_create(void) +{ + return MEM_callocN(sizeof(AnimKeylistDrawList), __func__); +} - draw_keylist(v2d, keylist, ypos, yscale_fac, false, saction_flag); +static void ED_keylist_draw_list_build_keylists(AnimKeylistDrawList *draw_list) +{ + LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { + ED_keylist_draw_list_elem_build_keylist(elem); + } +} - ED_keylist_free(keylist); +static void ED_keylist_draw_list_draw(AnimKeylistDrawList *draw_list, View2D *v2d) +{ + LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { + ED_keylist_draw_list_elem_draw(elem, v2d); + } } -void draw_scene_channel( - View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag) +void ED_keylist_draw_list_flush(AnimKeylistDrawList *draw_list, View2D *v2d) { - struct AnimKeylist *keylist = ED_keylist_create(); + ED_keylist_draw_list_build_keylists(draw_list); + ED_keylist_draw_list_draw(draw_list, v2d); +} - saction_flag &= ~SACTION_SHOW_EXTREMES; +void ED_keylist_draw_list_free(AnimKeylistDrawList *draw_list) +{ + LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { + ED_keylist_free(elem->keylist); + } + BLI_freelistN(&draw_list->channels); + MEM_freeN(draw_list); +} - scene_to_keylist(ads, sce, keylist, saction_flag); +static AnimKeylistDrawListElem *ed_keylist_draw_list_add_elem( + AnimKeylistDrawList *draw_list, + eAnimKeylistDrawListElemType elem_type, + float ypos, + float yscale_fac, + eSAction_Flag saction_flag) +{ + AnimKeylistDrawListElem *draw_elem = MEM_callocN(sizeof(AnimKeylistDrawListElem), __func__); + BLI_addtail(&draw_list->channels, draw_elem); + draw_elem->type = elem_type; + draw_elem->keylist = ED_keylist_create(); + draw_elem->ypos = ypos; + draw_elem->yscale_fac = yscale_fac; + draw_elem->saction_flag = saction_flag; + return draw_elem; +} - draw_keylist(v2d, keylist, ypos, yscale_fac, false, saction_flag); +/* *************************** Channel Drawing Funcs *************************** */ - ED_keylist_free(keylist); +void draw_summary_channel(struct AnimKeylistDrawList *draw_list, + bAnimContext *ac, + float ypos, + float yscale_fac, + int saction_flag) +{ + saction_flag &= ~SACTION_SHOW_EXTREMES; + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_SUMMARY, ypos, yscale_fac, saction_flag); + draw_elem->ac = ac; } -void draw_object_channel( - View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag) +void draw_scene_channel(AnimKeylistDrawList *draw_list, + bDopeSheet *ads, + Scene *sce, + float ypos, + float yscale_fac, + int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); - saction_flag &= ~SACTION_SHOW_EXTREMES; - - ob_to_keylist(ads, ob, keylist, saction_flag); - - draw_keylist(v2d, keylist, ypos, yscale_fac, false, saction_flag); - - ED_keylist_free(keylist); + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_SCENE, ypos, yscale_fac, saction_flag); + draw_elem->ads = ads; + draw_elem->sce = sce; } -void draw_fcurve_channel( - View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag) +void draw_object_channel(AnimKeylistDrawList *draw_list, + bDopeSheet *ads, + Object *ob, + float ypos, + float yscale_fac, + int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); - - bool locked = (fcu->flag & FCURVE_PROTECTED) || - ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || - ((adt && adt->action) && ID_IS_LINKED(adt->action)); - - fcurve_to_keylist(adt, fcu, keylist, saction_flag); - - draw_keylist(v2d, keylist, ypos, yscale_fac, locked, saction_flag); - - ED_keylist_free(keylist); + saction_flag &= ~SACTION_SHOW_EXTREMES; + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_OBJECT, ypos, yscale_fac, saction_flag); + draw_elem->ads = ads; + draw_elem->ob = ob; } -void draw_agroup_channel( - View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag) +void draw_fcurve_channel(AnimKeylistDrawList *draw_list, + AnimData *adt, + FCurve *fcu, + float ypos, + float yscale_fac, + int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); + const bool locked = (fcu->flag & FCURVE_PROTECTED) || + ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || + ((adt && adt->action) && ID_IS_LINKED(adt->action)); + + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_FCURVE, ypos, yscale_fac, saction_flag); + draw_elem->adt = adt; + draw_elem->fcu = fcu; + draw_elem->channel_locked = locked; +} +void draw_agroup_channel(AnimKeylistDrawList *draw_list, + AnimData *adt, + bActionGroup *agrp, + float ypos, + float yscale_fac, + int saction_flag) +{ bool locked = (agrp->flag & AGRP_PROTECTED) || ((adt && adt->action) && ID_IS_LINKED(adt->action)); - agroup_to_keylist(adt, agrp, keylist, saction_flag); - - draw_keylist(v2d, keylist, ypos, yscale_fac, locked, saction_flag); - - ED_keylist_free(keylist); + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_AGROUP, ypos, yscale_fac, saction_flag); + draw_elem->adt = adt; + draw_elem->agrp = agrp; + draw_elem->channel_locked = locked; } -void draw_action_channel( - View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag) +void draw_action_channel(AnimKeylistDrawList *draw_list, + AnimData *adt, + bAction *act, + float ypos, + float yscale_fac, + int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); - - bool locked = (act && ID_IS_LINKED(act)); - + const bool locked = (act && ID_IS_LINKED(act)); saction_flag &= ~SACTION_SHOW_EXTREMES; - action_to_keylist(adt, act, keylist, saction_flag); - - draw_keylist(v2d, keylist, ypos, yscale_fac, locked, saction_flag); - - ED_keylist_free(keylist); + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_ACTION, ypos, yscale_fac, saction_flag); + draw_elem->adt = adt; + draw_elem->act = act; + draw_elem->channel_locked = locked; } void draw_gpencil_channel( @@ -560,34 +699,32 @@ void draw_gpencil_channel( ED_keylist_free(keylist); } -void draw_gpl_channel( - View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag) +void draw_gpl_channel(AnimKeylistDrawList *draw_list, + bDopeSheet *ads, + bGPDlayer *gpl, + float ypos, + float yscale_fac, + int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); - bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0; - - gpl_to_keylist(ads, gpl, keylist); - - draw_keylist(v2d, keylist, ypos, yscale_fac, locked, saction_flag); - - ED_keylist_free(keylist); + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_GP_LAYER, ypos, yscale_fac, saction_flag); + draw_elem->ads = ads; + draw_elem->gpl = gpl; + draw_elem->channel_locked = locked; } -void draw_masklay_channel(View2D *v2d, +void draw_masklay_channel(AnimKeylistDrawList *draw_list, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag) { - struct AnimKeylist *keylist = ED_keylist_create(); - bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0; - - mask_to_keylist(ads, masklay, keylist); - - draw_keylist(v2d, keylist, ypos, yscale_fac, locked, saction_flag); - - ED_keylist_free(keylist); + AnimKeylistDrawListElem *draw_elem = ed_keylist_draw_list_add_elem( + draw_list, ANIM_KEYLIST_MASK_LAYER, ypos, yscale_fac, saction_flag); + draw_elem->ads = ads; + draw_elem->masklay = masklay; + draw_elem->channel_locked = locked; } diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index d2d22dd38dc..c9bbf58ff7a 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -28,6 +28,7 @@ extern "C" { #endif struct AnimData; +struct AnimKeylistDrawList; struct FCurve; struct MaskLayer; struct Object; @@ -61,43 +62,46 @@ void draw_keyframe_shape(float x, /* Channel Drawing ------------------ */ /* F-Curve */ -void draw_fcurve_channel(struct View2D *v2d, +void draw_fcurve_channel(struct AnimKeylistDrawList *draw_list, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac, int saction_flag); /* Action Group Summary */ -void draw_agroup_channel(struct View2D *v2d, +void draw_agroup_channel(struct AnimKeylistDrawList *draw_list, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag); /* Action Summary */ -void draw_action_channel(struct View2D *v2d, +void draw_action_channel(struct AnimKeylistDrawList *draw_list, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac, int saction_flag); /* Object Summary */ -void draw_object_channel(struct View2D *v2d, +void draw_object_channel(struct AnimKeylistDrawList *draw_list, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac, int saction_flag); /* Scene Summary */ -void draw_scene_channel(struct View2D *v2d, +void draw_scene_channel(struct AnimKeylistDrawList *draw_list, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac, int saction_flag); /* DopeSheet Summary */ -void draw_summary_channel( - struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac, int saction_flag); +void draw_summary_channel(struct AnimKeylistDrawList *draw_list, + struct bAnimContext *ac, + float ypos, + float yscale_fac, + int saction_flag); /* Grease Pencil datablock summary */ void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, @@ -106,20 +110,24 @@ void draw_gpencil_channel(struct View2D *v2d, float yscale_fac, int saction_flag); /* Grease Pencil Layer */ -void draw_gpl_channel(struct View2D *v2d, +void draw_gpl_channel(struct AnimKeylistDrawList *draw_list, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag); /* Mask Layer */ -void draw_masklay_channel(struct View2D *v2d, +void draw_masklay_channel(struct AnimKeylistDrawList *draw_list, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag); +struct AnimKeylistDrawList *ED_keylist_draw_list_create(void); +void ED_keylist_draw_list_flush(struct AnimKeylistDrawList *draw_list, struct View2D *v2d); +void ED_keylist_draw_list_free(struct AnimKeylistDrawList *draw_list); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index ce07b9c5fad..903754f4fb1 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -302,6 +302,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region ymax = ACHANNEL_FIRST_TOP(ac); + struct AnimKeylistDrawList *draw_list = ED_keylist_draw_list_create(); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { float ymin = ymax - ACHANNEL_HEIGHT(ac); float ycenter = (ymin + ymax) / 2.0f; @@ -316,34 +318,41 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: - draw_summary_channel(v2d, ale->data, ycenter, ac->yscale_fac, action_flag); + draw_summary_channel(draw_list, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_SCE: - draw_scene_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); + draw_scene_channel( + draw_list, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_OB: - draw_object_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); + draw_object_channel( + draw_list, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_ACT: - draw_action_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); + draw_action_channel( + draw_list, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GROUP: - draw_agroup_channel(v2d, adt, ale->data, ycenter, ac->yscale_fac, action_flag); + draw_agroup_channel(draw_list, adt, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_FCURVE: - draw_fcurve_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); + draw_fcurve_channel( + draw_list, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GPFRAME: - draw_gpl_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); + draw_gpl_channel(draw_list, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_MASKLAY: - draw_masklay_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); + draw_masklay_channel(draw_list, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; } } } } + ED_keylist_draw_list_flush(draw_list, v2d); + ED_keylist_draw_list_free(draw_list); + /* free temporary channels used for drawing */ ANIM_animdata_freelist(&anim_data); } -- cgit v1.2.3 From bb487bc2bc82c02922722efb3ca1d2570d907ad9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 11 Aug 2021 16:59:09 +0200 Subject: Fix T89984: Improve Icon previews reflective and transmissive materials. Before this commit rendering material icons the floor will is hidden. This reduces the readability of reflective/refractive materials. check patch for additional screenshots and notes. This patch will switch the floor material that uses ray visibility tricks to render a floor for reflective rays. Eevee uses screen space reflections that makes this a different problem. There is nothing else drawn in the scene in screen space so we need a different trick. Using math we convert a reflective ray to UV space and generate a world that projects a checker pattern to infinity. As now the floor is in the world it is being reflected via a cubemap. As the film is transparent the background (including the floor isn't rendered) In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this approximation. We tried lightprobes but that wasn't able to do the trick. Using the compositor would lead to more memory usage (render layers and intermediate buffers) and slower performance. Solution has been validated with Simon Reviewed By: sybren, Severin Differential Revision: https://developer.blender.org/D11988 --- source/blender/editors/render/render_preview.c | 92 +++++++++++++++++++++----- 1 file changed, 77 insertions(+), 15 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index bd4c83c107e..95351de45f0 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -47,6 +47,7 @@ #include "DNA_collection_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -265,6 +266,11 @@ static const char *preview_collection_name(const ePreviewType pr_type) } } +static bool render_engine_supports_ray_visibility(const Scene *sce) +{ + return !STREQ(sce->r.engine, RE_engine_id_BLENDER_EEVEE); +} + static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type) { /* Set appropriate layer as visible. */ @@ -281,29 +287,60 @@ static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePr } } -static void switch_preview_floor_visibility(ViewLayer *view_layer, +static const char *preview_floor_material_name(const Scene *scene, + const ePreviewRenderMethod pr_method) +{ + if (pr_method == PR_ICON_RENDER && render_engine_supports_ray_visibility(scene)) { + return "FloorHidden"; + } + return "Floor"; +} + +static void switch_preview_floor_material(Main *pr_main, + Mesh *me, + const Scene *scene, + const ePreviewRenderMethod pr_method) +{ + if (me->totcol == 0) { + return; + } + + const char *material_name = preview_floor_material_name(scene, pr_method); + Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2); + if (mat) { + me->mat[0] = mat; + } +} + +static void switch_preview_floor_visibility(Main *pr_main, + const Scene *scene, + ViewLayer *view_layer, const ePreviewRenderMethod pr_method) { /* Hide floor for icon renders. */ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { if (STREQ(base->object->id.name + 2, "Floor")) { + base->object->visibility_flag &= ~OB_HIDE_RENDER; if (pr_method == PR_ICON_RENDER) { - base->object->visibility_flag |= OB_HIDE_RENDER; + if (!render_engine_supports_ray_visibility(scene)) { + base->object->visibility_flag |= OB_HIDE_RENDER; + } } - else { - base->object->visibility_flag &= ~OB_HIDE_RENDER; + if (base->object->type == OB_MESH) { + switch_preview_floor_material(pr_main, base->object->data, scene, pr_method); } } } } -static void set_preview_visibility(Scene *scene, +static void set_preview_visibility(Main *pr_main, + Scene *scene, ViewLayer *view_layer, const ePreviewType pr_type, const ePreviewRenderMethod pr_method) { switch_preview_collection_visibilty(view_layer, pr_type); - switch_preview_floor_visibility(view_layer, pr_method); + switch_preview_floor_visibility(pr_main, scene, view_layer, pr_method); BKE_layer_collection_sync(scene, view_layer); } @@ -357,10 +394,31 @@ static ID *duplicate_ids(ID *id, const bool allow_failure) } } -static World *preview_get_world(Main *pr_main) +static const char *preview_world_name(const Scene *sce, + const ID_Type id_type, + const ePreviewRenderMethod pr_method) +{ + /* When rendering material icons the floor will not be shown in the output. Cycles will use a + * material trick to show the floor in the reflections, but hide the floor for camera rays. For + * Eevee we use a transparent world that has a projected grid. + * + * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this + * approximation. + */ + if (id_type == ID_MA && pr_method == PR_ICON_RENDER && + !render_engine_supports_ray_visibility(sce)) { + return "WorldFloor"; + } + return "World"; +} + +static World *preview_get_world(Main *pr_main, + const Scene *sce, + const ID_Type id_type, + const ePreviewRenderMethod pr_method) { World *result = NULL; - const char *world_name = "World"; + const char *world_name = preview_world_name(sce, id_type, pr_method); result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2); /* No world found return first world. */ @@ -380,9 +438,13 @@ static void preview_sync_exposure(World *dst, const World *src) dst->range = src->range; } -static World *preview_prepare_world(Main *pr_main, const World *world) +static World *preview_prepare_world(Main *pr_main, + const Scene *sce, + const World *world, + const ID_Type id_type, + const ePreviewRenderMethod pr_method) { - World *result = preview_get_world(pr_main); + World *result = preview_get_world(pr_main, sce, id_type, pr_method); if (world) { preview_sync_exposure(result, world); } @@ -436,7 +498,7 @@ static Scene *preview_prepare_scene( sce->r.cfra = scene->r.cfra; /* Setup the world. */ - sce->world = preview_prepare_world(pr_main, scene->world); + sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method); if (id_type == ID_TE) { /* Texture is not actually rendered with engine, just set dummy value. */ @@ -458,7 +520,7 @@ static Scene *preview_prepare_scene( /* Use current scene world to light sphere. */ sce->world = preview_get_localized_world(sp, scene->world); } - else if (sce->world) { + else if (sce->world && sp->pr_method != PR_ICON_RENDER) { /* Use a default world color. Using the current * scene world can be slow if it has big textures. */ sce->world->use_nodes = false; @@ -472,7 +534,7 @@ static Scene *preview_prepare_scene( sp->pr_main == G_pr_main_grease_pencil) ? MA_SPHERE_A : mat->pr_type; - set_preview_visibility(sce, view_layer, preview_type, sp->pr_method); + set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method); if (sp->pr_method != PR_ICON_RENDER) { if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { @@ -536,7 +598,7 @@ static Scene *preview_prepare_scene( BLI_addtail(&pr_main->lights, la); } - set_preview_visibility(sce, view_layer, MA_LAMP, sp->pr_method); + set_preview_visibility(pr_main, sce, view_layer, MA_LAMP, sp->pr_method); if (sce->world) { /* Only use lighting from the light. */ @@ -571,7 +633,7 @@ static Scene *preview_prepare_scene( BLI_addtail(&pr_main->worlds, wrld); } - set_preview_visibility(sce, view_layer, MA_SKY, sp->pr_method); + set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method); sce->world = wrld; if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) { -- cgit v1.2.3 From cd1bb63159215396662ce49c8bc8d6d437114093 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 11 Aug 2021 13:55:58 -0700 Subject: BLF: Do Not Cache Unused Rendered Glyphs The loading of a font size or style renders bitmaps of the characters 0-255 and stores them in a cache. But glyphs 128-255 in this cache are not accessible. What used to be ansi high-bit characters are now multi- byte UTF-8 sequences. Therefore this patch reduces the glyph_ascii_table size to 128 and only caches characters 32-127, the visible portion of ASCII, which greatly reduces the time to load a font. See D12189 for more details. Differential Revision: https://developer.blender.org/D12189 Reviewed by Campbell Barton --- source/blender/blenfont/intern/blf_font.c | 3 ++- source/blender/blenfont/intern/blf_internal_types.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 6e2be4a8353..8e306730e3c 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -317,7 +317,8 @@ static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc) /* build ascii on demand */ if (glyph_ascii_table['0'] == NULL) { GlyphBLF *g; - for (uint i = 0; i < 256; i++) { + /* Skip control characters and just cache rendered glyphs for visible ASCII range. */ + for (uint i = 32; i < 128; i++) { g = blf_glyph_search(gc, i); if (!g) { FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 36bb8769306..6816c97321d 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -71,7 +71,7 @@ typedef struct GlyphCacheBLF { ListBase bucket[257]; /* fast ascii lookup */ - struct GlyphBLF *glyph_ascii_table[256]; + struct GlyphBLF *glyph_ascii_table[128]; /* texture array, to draw the glyphs. */ GPUTexture *texture; -- cgit v1.2.3 From 48c8f9fc9a34360b23e03aaae41cdbf0b4fa4424 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 11 Aug 2021 16:57:56 -0600 Subject: Fix: DNA struct alignment on 32 bit Some of the dna structs were not properly aligned for 32 bit builds causing issues for some of the 32 platforms Debian builds for. Reviewed By: sergey, brecht Differential Revision: https://developer.blender.org/D9389 --- source/blender/makesdna/DNA_gpencil_types.h | 1 + source/blender/makesdna/DNA_mesh_types.h | 1 + source/blender/makesdna/DNA_modifier_types.h | 25 +++++++++++++++++++++++++ source/blender/makesdna/DNA_object_types.h | 1 + source/blender/makesdna/DNA_sequence_types.h | 1 + 5 files changed, 29 insertions(+) (limited to 'source/blender') diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 380d8ad1249..68bd2961f23 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -324,6 +324,7 @@ typedef struct bGPDstroke { struct bGPDcurve *editcurve; bGPDstroke_Runtime runtime; + void *_pad5; } bGPDstroke; /** #bGPDstroke.flag */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 932f4715298..97f14b2195d 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -231,6 +231,7 @@ typedef struct Mesh { * default and Face Sets can be used without affecting the color of the mesh. */ int face_sets_color_default; + void *_pad2; Mesh_Runtime runtime; } Mesh; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index f66de378c35..1bebbc35747 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -136,6 +136,7 @@ typedef struct ModifierData { /* Runtime field which contains runtime data which is specific to a modifier type. */ void *runtime; + void *_pad1; } ModifierData; typedef enum { @@ -215,6 +216,7 @@ typedef struct LatticeModifierData { float strength; short flag; char _pad[2]; + void *_pad1; } LatticeModifierData; /* Lattice modifier flags. */ @@ -232,6 +234,7 @@ typedef struct CurveModifierData { short defaxis; short flag; char _pad[4]; + void *_pad1; } CurveModifierData; /* Curve modifier flags */ @@ -283,6 +286,7 @@ typedef struct MaskModifierData { /** Flags for various things. */ short flag; float threshold; + void *_pad1; } MaskModifierData; /* Mask Modifier -> mode */ @@ -373,6 +377,7 @@ typedef struct MirrorModifierData { float uv_offset[2]; float uv_offset_copy[2]; struct Object *mirror_ob; + void *_pad1; } MirrorModifierData; /* MirrorModifierData->flag */ @@ -451,6 +456,7 @@ typedef struct BevelModifierData { /** Curve info for the custom profile */ struct CurveProfile *custom_profile; + void *_pad2; } BevelModifierData; /* BevelModifierData->flags and BevelModifierData->lim_flags */ @@ -535,6 +541,7 @@ typedef struct FluidModifierData { float time; /** Domain, inflow, outflow, .... */ int type; + void *_pad1; } FluidModifierData; /* Fluid modifier flags */ @@ -680,6 +687,7 @@ typedef struct CastModifierData { /** MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag, type; + void *_pad1; } CastModifierData; /* Cast modifier flags */ @@ -725,6 +733,7 @@ typedef struct WaveModifierData { float timeoffs, lifetime; char _pad1[4]; + void *_pad2; } WaveModifierData; /* WaveModifierData.flag */ @@ -797,6 +806,7 @@ typedef struct HookModifierData { float force; /** Optional vertexgroup name, MAX_VGROUP_NAME. */ char name[64]; + void *_pad1; } HookModifierData; typedef struct SoftbodyModifierData { @@ -1001,6 +1011,7 @@ typedef struct ParticleSystemModifierData { int totdmvert, totdmedge, totdmface; short flag; char _pad[2]; + void *_pad1; } ParticleSystemModifierData; typedef enum { @@ -1037,6 +1048,7 @@ typedef struct ParticleInstanceModifierData { char index_layer_name[64]; /** MAX_CUSTOMDATA_LAYER_NAME. */ char value_layer_name[64]; + void *_pad1; } ParticleInstanceModifierData; typedef enum { @@ -1057,6 +1069,7 @@ typedef struct ExplodeModifierData { float protect; /** MAX_CUSTOMDATA_LAYER_NAME. */ char uvname[64]; + void *_pad1; } ExplodeModifierData; typedef struct MultiresModifierData { @@ -1086,6 +1099,7 @@ typedef struct FluidsimModifierData { /** Definition is in DNA_object_fluidsim_types.h. */ struct FluidsimSettings *fss; + void *_pad1; } FluidsimModifierData; /* DEPRECATED, only used for versioning. */ @@ -1202,6 +1216,7 @@ typedef struct SimpleDeformModifierData { char deform_axis; char flag; + void *_pad1; } SimpleDeformModifierData; /* SimpleDeform->flag */ @@ -1310,6 +1325,7 @@ typedef struct ScrewModifierData { short flag; char axis; char _pad[5]; + void *_pad1; } ScrewModifierData; enum { @@ -1434,6 +1450,7 @@ typedef struct WarpModifierData { char flag; char falloff_type; char _pad[6]; + void *_pad1; } WarpModifierData; /* WarpModifierData->flag */ @@ -1497,6 +1514,7 @@ typedef struct WeightVGEditModifierData { /* Padding... */ char _pad0[4]; + void *_pad1; } WeightVGEditModifierData; /* WeightVGEdit flags. */ @@ -2064,6 +2082,7 @@ typedef struct DataTransferModifierData { char defgrp_name[64]; int flags; + void *_pad2; } DataTransferModifierData; /* DataTransferModifierData.flags */ @@ -2094,6 +2113,7 @@ typedef struct NormalEditModifierData { float mix_limit; float offset[3]; char _pad0[4]; + void *_pad1; } NormalEditModifierData; /* NormalEditModifierData.mode */ @@ -2154,6 +2174,7 @@ typedef struct MeshSeqCacheModifierData { float last_lookup_time; int _pad1; + void *_pad2; } MeshSeqCacheModifierData; /* MeshSeqCacheModifierData.read_flag */ @@ -2198,6 +2219,7 @@ typedef struct SurfaceDeformModifierData { float mat[4][4]; float strength; char defgrp_name[64]; + void *_pad1; } SurfaceDeformModifierData; /* Surface Deform modifier flags */ @@ -2259,6 +2281,7 @@ typedef struct NodesModifierData { /* Contains logged information from the last evaluation. This can be used to help the user to * debug a node tree. */ void *runtime_eval_log; + void *_pad1; } NodesModifierData; typedef struct MeshToVolumeModifierData { @@ -2286,6 +2309,7 @@ typedef struct MeshToVolumeModifierData { float density; char _pad2[4]; + void *_pad3; } MeshToVolumeModifierData; /* MeshToVolumeModifierData->resolution_mode */ @@ -2332,6 +2356,7 @@ typedef struct VolumeToMeshModifierData { /** MAX_NAME */ char grid_name[64]; + void *_pad1; } VolumeToMeshModifierData; /** VolumeToMeshModifierData->resolution_mode */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e7091c78f71..c6d6334118f 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -433,6 +433,7 @@ typedef struct Object { ObjectLineArt lineart; /** Runtime evaluation data (keep last). */ + void *_pad9; Object_Runtime runtime; } Object; diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index af524ff4866..df18501d2ea 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -296,6 +296,7 @@ typedef struct Editing { int64_t disk_cache_timestamp; EditingRuntime runtime; + void *_pad1; } Editing; /* ************* Effect Variable Structs ********* */ -- cgit v1.2.3 From 45d100208e8fc07e65d4cad303fa353e85bf8747 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 11 Aug 2021 19:20:51 -0600 Subject: Makesdna: Fix detecting 32 bit padding issues. Makesdna fails to detect issues in 32 bit code that can only be resolved by adding a padding pointer. We never noticed since we ourselves no longer build for 32 bit, but debian's 32 bit builds got bitten by this A rather extensive explanation on why this is alignment requirement is there can be found in this comment: https://developer.blender.org/D9389#233034 Differential Revision: https://developer.blender.org/D12188 Reviewed by: sergey, campbellbarton --- source/blender/makesdna/intern/makesdna.c | 69 ++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index f2a75a60a44..8324db1a9c8 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -165,6 +165,10 @@ static char **names; static char **types; /** At `types_size[a]` is the size of type `a` on this systems bitness (32 or 64). */ static short *types_size_native; +/** Contains align requirements for a struct on 32 bit systems. */ +static short *types_align_32; +/** Contains align requirements for a struct on 64 bit systems. */ +static short *types_align_64; /** Contains sizes as they are calculated on 32 bit systems. */ static short *types_size_32; /** Contains sizes as they are calculated on 64 bit systems. */ @@ -406,6 +410,8 @@ static int add_type(const char *str, int size) types_size_native[index] = size; types_size_32[index] = size; types_size_64[index] = size; + types_align_32[index] = size; + types_align_64[index] = size; } return index; } @@ -419,7 +425,8 @@ static int add_type(const char *str, int size) types_size_native[types_len] = size; types_size_32[types_len] = size; types_size_64[types_len] = size; - + types_align_32[types_len] = size; + types_align_64[types_len] = size; if (types_len >= max_array_len) { printf("too many types\n"); return types_len - 1; @@ -966,7 +973,9 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char int size_native = 0; int size_32 = 0; int size_64 = 0; - bool has_pointer = false; + /* Sizes of the largest field in a struct. */ + int max_align_32 = 0; + int max_align_64 = 0; /* check all elements in struct */ for (int b = 0; b < structpoin[1]; b++, sp += 2) { @@ -995,7 +1004,6 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char /* is it a pointer or function pointer? */ if (cp[0] == '*' || cp[1] == '*') { - has_pointer = 1; /* has the name an extra length? (array) */ int mul = 1; if (cp[namelen - 1] == ']') { @@ -1042,6 +1050,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char size_native += sizeof(void *) * mul; size_32 += 4 * mul; size_64 += 8 * mul; + max_align_32 = MAX2(max_align_32, 4); + max_align_64 = MAX2(max_align_64, 8); } else if (cp[0] == '[') { /* parsing can cause names "var" and "[3]" @@ -1087,6 +1097,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char size_native += mul * types_size_native[type]; size_32 += mul * types_size_32[type]; size_64 += mul * types_size_64[type]; + max_align_32 = MAX2(max_align_32, types_align_32[type]); + max_align_64 = MAX2(max_align_64, types_align_64[type]); } else { size_native = 0; @@ -1103,16 +1115,42 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char types_size_native[structtype] = size_native; types_size_32[structtype] = size_32; types_size_64[structtype] = size_64; - /* Two ways to detect if a struct contains a pointer: - * has_pointer is set or size_native doesn't match any of 32/64bit lengths. */ - if (has_pointer || size_64 != size_native || size_32 != size_native) { - if (size_64 % 8) { + types_align_32[structtype] = max_align_32; + types_align_64[structtype] = max_align_64; + + /* Santiy check 1: alignment should never be 0. */ + BLI_assert(max_align_32); + BLI_assert(max_align_64); + + /* Santiy check 2: alignment should always be equal or smaller than the maximum + * size of a build in type which is 8 bytes (ie int64_t or double). */ + BLI_assert(max_align_32 <= 8); + BLI_assert(max_align_64 <= 8); + + if (size_32 % max_align_32) { + /* There is an one odd case where only the 32 bit struct has alignment issues + * and the 64 bit does not, that can only be fixed by adding a padding pointer + * to the struct to resolve the problem. */ + if ((size_64 % max_align_64 == 0) && (size_32 % max_align_32 == 4)) { fprintf(stderr, - "Sizeerror 8 in struct: %s (add %d bytes)\n", + "Sizeerror in 32 bit struct: %s (add paddding pointer)\n", + types[structtype]); + } + else { + fprintf(stderr, + "Sizeerror in 32 bit struct: %s (add %d bytes)\n", types[structtype], - size_64 % 8); - dna_error = 1; + max_align_32 - (size_32 % max_align_32)); } + dna_error = 1; + } + + if (size_64 % max_align_64) { + fprintf(stderr, + "Sizeerror in 64 bit struct: %s (add %d bytes)\n", + types[structtype], + max_align_64 - (size_64 % max_align_64)); + dna_error = 1; } if (size_native % 4 && !ELEM(size_native, 1, 2)) { @@ -1229,6 +1267,9 @@ static int make_structDNA(const char *base_directory, types_size_native = MEM_callocN(sizeof(short) * max_array_len, "types_size_native"); types_size_32 = MEM_callocN(sizeof(short) * max_array_len, "types_size_32"); types_size_64 = MEM_callocN(sizeof(short) * max_array_len, "types_size_64"); + types_align_32 = MEM_callocN(sizeof(short) * max_array_len, "types_size_32"); + types_align_64 = MEM_callocN(sizeof(short) * max_array_len, "types_size_64"); + structs = MEM_callocN(sizeof(short *) * max_array_len, "structs"); /* Build versioning data */ @@ -1317,7 +1358,11 @@ static int make_structDNA(const char *base_directory, sp += 2; /* ? num_types was elem? */ for (b = 0; b < num_types; b++, sp += 2) { - printf(" %s %s\n", types[sp[0]], names[sp[1]]); + printf(" %s %s allign32:%d, allign64:%d\n", + types[sp[0]], + names[sp[1]], + types_align_32[sp[0]], + types_align_64[sp[0]]); } } } @@ -1439,6 +1484,8 @@ static int make_structDNA(const char *base_directory, MEM_freeN(types_size_native); MEM_freeN(types_size_32); MEM_freeN(types_size_64); + MEM_freeN(types_align_32); + MEM_freeN(types_align_64); MEM_freeN(structs); BLI_memarena_free(mem_arena); -- cgit v1.2.3 From 4f61843a7e2fc7d92a630379c14cc87a6e892d6f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 14:34:39 +1000 Subject: Cleanup: remove *.orig file from 6a9d7139f7d05e0c51827a3a4b862c0547dc0513 --- .../blender/blenkernel/intern/mesh_normals.cc.orig | 2217 -------------------- 1 file changed, 2217 deletions(-) delete mode 100644 source/blender/blenkernel/intern/mesh_normals.cc.orig (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh_normals.cc.orig b/source/blender/blenkernel/intern/mesh_normals.cc.orig deleted file mode 100644 index 18d384e8589..00000000000 --- a/source/blender/blenkernel/intern/mesh_normals.cc.orig +++ /dev/null @@ -1,2217 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - */ - -/** \file - * \ingroup bke - * - * Mesh normal calculation functions. - * - * \see bmesh_mesh_normals.c for the equivalent #BMesh functionality. - */ - -#include - -#include "CLG_log.h" - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BLI_alloca.h" -#include "BLI_bitmap.h" - -#include "BLI_linklist.h" -#include "BLI_linklist_stack.h" -#include "BLI_math.h" -#include "BLI_memarena.h" -#include "BLI_stack.h" -#include "BLI_task.h" -#include "BLI_utildefines.h" - -#include "BKE_customdata.h" -#include "BKE_editmesh_cache.h" -#include "BKE_global.h" -#include "BKE_mesh.h" - -<<<<<<< Updated upstream -#include "atomic_ops.h" - -// #define DEBUG_TIME -======= -#define DEBUG_TIME ->>>>>>> Stashed changes - -#ifdef DEBUG_TIME -# include "PIL_time.h" -# include "PIL_time_utildefines.h" -#endif - -static CLG_LogRef LOG = {"bke.mesh_normals"}; - -/* -------------------------------------------------------------------- */ -/** \name Private Utility Functions - * \{ */ - -/** - * A thread-safe version of #add_v3_v3 that uses a spin-lock. - * - * \note Avoid using this when the chance of contention is high. - */ -static void add_v3_v3_atomic(float r[3], const float a[3]) -{ -#define FLT_EQ_NONAN(_fa, _fb) (*((const uint32_t *)&_fa) == *((const uint32_t *)&_fb)) - - float virtual_lock = r[0]; - while (true) { - /* This loops until following conditions are met: - * - `r[0]` has same value as virtual_lock (i.e. it did not change since last try). - * - `r[0]` was not `FLT_MAX`, i.e. it was not locked by another thread. */ - const float test_lock = atomic_cas_float(&r[0], virtual_lock, FLT_MAX); - if (_ATOMIC_LIKELY(FLT_EQ_NONAN(test_lock, virtual_lock) && (test_lock != FLT_MAX))) { - break; - } - virtual_lock = test_lock; - } - virtual_lock += a[0]; - r[1] += a[1]; - r[2] += a[2]; - - /* Second atomic operation to 'release' - * our lock on that vector and set its first scalar value. */ - /* Note that we do not need to loop here, since we 'locked' `r[0]`, - * nobody should have changed it in the mean time. */ - virtual_lock = atomic_cas_float(&r[0], FLT_MAX, virtual_lock); - BLI_assert(virtual_lock == FLT_MAX); - -#undef FLT_EQ_NONAN -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mesh Normal Calculation - * \{ */ - -void BKE_mesh_normals_tag_dirty(Mesh *mesh) -{ - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL; -} - -/** - * Call when there are no polygons. - */ -static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) -{ - for (int i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float no[3]; - - normalize_v3_v3(no, mv->co); - normal_float_to_short_v3(mv->no, no); - } -} - -/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(), - * and remove the function of the same name below, as that one doesn't seem to be - * called anywhere. */ -void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh) -{ - const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT); - - BKE_mesh_calc_normals_mapping_ex(mesh->mvert, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - nullptr, - mesh->mface, - mesh->totface, - nullptr, - nullptr, - only_face_normals); -} - -/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-nullptr - * and vertex normals are stored in actual mverts. - */ -void BKE_mesh_calc_normals_mapping(MVert *mverts, - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3]) -{ - BKE_mesh_calc_normals_mapping_ex(mverts, - numVerts, - mloop, - mpolys, - numLoops, - numPolys, - r_polyNors, - mfaces, - numFaces, - origIndexFace, - r_faceNors, - false); -} -/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */ -void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3], - const bool only_face_normals) -{ - float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors; - - if (numPolys == 0) { - if (only_face_normals == false) { - mesh_calc_normals_vert_fallback(mverts, numVerts); - } - return; - } - - /* if we are not calculating verts and no verts were passes then we have nothing to do */ - if ((only_face_normals == true) && (r_polyNors == nullptr) && (r_faceNors == nullptr)) { - CLOG_WARN(&LOG, "called with nothing to do"); - return; - } - - if (!pnors) { - pnors = (float(*)[3])MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__); - } - /* NO NEED TO ALLOC YET */ - /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ - - if (only_face_normals == false) { - /* vertex normals are optional, they require some extra calculations, - * so make them optional */ - BKE_mesh_calc_normals_poly( - mverts, nullptr, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); - } - else { - /* only calc poly normals */ - const MPoly *mp = mpolys; - for (int i = 0; i < numPolys; i++, mp++) { - BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); - } - } - - if (origIndexFace && - /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */ - fnors != nullptr && - numFaces) { - const MFace *mf = mfaces; - for (int i = 0; i < numFaces; i++, mf++, origIndexFace++) { - if (*origIndexFace < numPolys) { - copy_v3_v3(fnors[i], pnors[*origIndexFace]); - } - else { - /* eek, we're not corresponding to polys */ - CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad."); - } - } - } - - if (pnors != r_polyNors) { - MEM_freeN(pnors); - } - /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */ - - fnors = pnors = nullptr; -} - -struct MeshCalcNormalsData { - const MPoly *mpolys; - const MLoop *mloop; - MVert *mverts; - float (*pnors)[3]; - float (*vnors)[3]; -}; - -static void mesh_calc_normals_poly_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - const MPoly *mp = &data->mpolys[pidx]; - - BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]); -} - -static void mesh_calc_normals_poly_and_accum_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - const MPoly *mp = &data->mpolys[pidx]; - const MLoop *ml = &data->mloop[mp->loopstart]; - const MVert *mverts = data->mverts; - float(*vnors)[3] = data->vnors; - - float pnor_temp[3]; - float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; - - const int i_end = mp->totloop - 1; - - /* Polygon Normal and edge-vector */ - /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ - { - zero_v3(pnor); - /* Newell's Method */ - const float *v_curr = mverts[ml[i_end].v].co; - for (int i_next = 0; i_next <= i_end; i_next++) { - const float *v_next = mverts[ml[i_next].v].co; - add_newell_cross_v3_v3v3(pnor, v_curr, v_next); - v_curr = v_next; - } - if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { - pnor[2] = 1.0f; /* other axes set to 0.0 */ - } - } - - /* Accumulate angle weighted face normal into the vertex normal. */ - /* inline version of #accumulate_vertex_normals_poly_v3. */ - { - float edvec_prev[3], edvec_next[3], edvec_end[3]; - const float *v_curr = mverts[ml[i_end].v].co; - sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr); - normalize_v3(edvec_prev); - copy_v3_v3(edvec_end, edvec_prev); - - for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) { - const float *v_next = mverts[ml[i_next].v].co; - - /* Skip an extra normalization by reusing the first calculated edge. */ - if (i_next != i_end) { - sub_v3_v3v3(edvec_next, v_curr, v_next); - normalize_v3(edvec_next); - } - else { - copy_v3_v3(edvec_next, edvec_end); - } - - /* Calculate angle between the two poly edges incident on this vertex. */ - const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); - const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; - - add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); - v_curr = v_next; - copy_v3_v3(edvec_prev, edvec_next); - } - } -} - -static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata, - const int vidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - - MVert *mv = &data->mverts[vidx]; - float *no = data->vnors[vidx]; - - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); -} - -void BKE_mesh_calc_normals_poly(MVert *mverts, - float (*r_vertnors)[3], - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int UNUSED(numLoops), - int numPolys, - float (*r_polynors)[3], - const bool only_face_normals) -{ - float(*pnors)[3] = r_polynors; - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - - if (only_face_normals) { - BLI_assert((pnors != nullptr) || (numPolys == 0)); - BLI_assert(r_vertnors == nullptr); - - MeshCalcNormalsData data; - data.mpolys = mpolys; - data.mloop = mloop; - data.mverts = mverts; - data.pnors = pnors; - - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings); - return; - } - - float(*vnors)[3] = r_vertnors; - bool free_vnors = false; - - /* first go through and calculate normals for all the polys */ - if (vnors == nullptr) { - vnors = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__); - free_vnors = true; - } - else { - memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts); - } - - MeshCalcNormalsData data; - data.mpolys = mpolys; - data.mloop = mloop; - data.mverts = mverts; - data.pnors = pnors; - data.vnors = vnors; - - /* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */ - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_and_accum_cb, &settings); - - /* Normalize and validate computed vertex normals (`vnors`). */ - BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); - - if (free_vnors) { - MEM_freeN(vnors); - } -} - -void BKE_mesh_ensure_normals(Mesh *mesh) -{ - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - BKE_mesh_calc_normals(mesh); - } - BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0); -} - -/** - * Called after calculating all modifiers. - */ -void BKE_mesh_ensure_normals_for_display(Mesh *mesh) -{ - switch ((eMeshWrapperType)mesh->runtime.wrapper_type) { - case ME_WRAPPER_TYPE_MDATA: - /* Run code below. */ - break; - case ME_WRAPPER_TYPE_BMESH: { - struct BMEditMesh *em = mesh->edit_mesh; - EditMeshData *emd = mesh->runtime.edit_data; - if (emd->vertexCos) { - BKE_editmesh_cache_ensure_vert_normals(em, emd); - BKE_editmesh_cache_ensure_poly_normals(em, emd); - } - return; - } - } - - float(*poly_nors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); - const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0; - const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || - poly_nors == nullptr); - - if (do_vert_normals || do_poly_normals) { - const bool do_add_poly_nors_cddata = (poly_nors == nullptr); - if (do_add_poly_nors_cddata) { - poly_nors = (float(*)[3])MEM_malloc_arrayN( - (size_t)mesh->totpoly, sizeof(*poly_nors), __func__); - } - - /* calculate poly/vert normals */ - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - poly_nors, - !do_vert_normals); - - if (do_add_poly_nors_cddata) { - CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly); - } - - mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; - mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; - } -} - -/* Note that this does not update the CD_NORMAL layer, - * but does update the normals in the CD_MVERT layer. */ -void BKE_mesh_calc_normals(Mesh *mesh) -{ -#ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(BKE_mesh_calc_normals); -#endif - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - nullptr, - false); -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(BKE_mesh_calc_normals); -#endif - mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; -} - -void BKE_mesh_calc_normals_looptri(MVert *mverts, - int numVerts, - const MLoop *mloop, - const MLoopTri *looptri, - int looptri_num, - float (*r_tri_nors)[3]) -{ - float(*tnorms)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms"); - float(*fnors)[3] = (r_tri_nors) ? r_tri_nors : - (float(*)[3])MEM_calloc_arrayN( - (size_t)looptri_num, sizeof(*fnors), "meshnormals"); - - if (!tnorms || !fnors) { - goto cleanup; - } - - for (int i = 0; i < looptri_num; i++) { - const MLoopTri *lt = &looptri[i]; - float *f_no = fnors[i]; - const uint vtri[3] = { - mloop[lt->tri[0]].v, - mloop[lt->tri[1]].v, - mloop[lt->tri[2]].v, - }; - - normal_tri_v3(f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co); - - accumulate_vertex_normals_tri_v3(tnorms[vtri[0]], - tnorms[vtri[1]], - tnorms[vtri[2]], - f_no, - mverts[vtri[0]].co, - mverts[vtri[1]].co, - mverts[vtri[2]].co); - } - - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - for (int i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float *no = tnorms[i]; - - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); - } - -cleanup: - MEM_freeN(tnorms); - - if (fnors != r_tri_nors) { - MEM_freeN(fnors); - } -} - -void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, - const int numLoops, - const char data_type) -{ - if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) { - MemArena *mem; - - if (!lnors_spacearr->mem) { - lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } - mem = lnors_spacearr->mem; - lnors_spacearr->lspacearr = (MLoopNorSpace **)BLI_memarena_calloc( - mem, sizeof(MLoopNorSpace *) * (size_t)numLoops); - lnors_spacearr->loops_pool = (LinkNode *)BLI_memarena_alloc( - mem, sizeof(LinkNode) * (size_t)numLoops); - - lnors_spacearr->num_spaces = 0; - } - BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); - lnors_spacearr->data_type = data_type; -} - -/** - * Utility for multi-threaded calculation that ensures - * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr` - * that would cause it not to be thread safe. - * - * \note This works as long as threads never operate on the same loops at once. - */ -void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, - MLoopNorSpaceArray *lnors_spacearr_tls) -{ - *lnors_spacearr_tls = *lnors_spacearr; - lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); -} - -/** - * Utility for multi-threaded calculation - * that merges `lnors_spacearr_tls` into `lnors_spacearr`. - */ -void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, - MLoopNorSpaceArray *lnors_spacearr_tls) -{ - BLI_assert(lnors_spacearr->data_type == lnors_spacearr_tls->data_type); - BLI_assert(lnors_spacearr->mem != lnors_spacearr_tls->mem); - lnors_spacearr->num_spaces += lnors_spacearr_tls->num_spaces; - BLI_memarena_merge(lnors_spacearr->mem, lnors_spacearr_tls->mem); - BLI_memarena_free(lnors_spacearr_tls->mem); - lnors_spacearr_tls->mem = nullptr; - BKE_lnor_spacearr_clear(lnors_spacearr_tls); -} - -void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) -{ - lnors_spacearr->num_spaces = 0; - lnors_spacearr->lspacearr = nullptr; - lnors_spacearr->loops_pool = nullptr; - if (lnors_spacearr->mem != nullptr) { - BLI_memarena_clear(lnors_spacearr->mem); - } -} - -void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) -{ - lnors_spacearr->num_spaces = 0; - lnors_spacearr->lspacearr = nullptr; - lnors_spacearr->loops_pool = nullptr; - BLI_memarena_free(lnors_spacearr->mem); - lnors_spacearr->mem = nullptr; -} - -MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) -{ - lnors_spacearr->num_spaces++; - return (MLoopNorSpace *)BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace)); -} - -/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */ -#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) - -/* Should only be called once. - * Beware, this modifies ref_vec and other_vec in place! - * In case no valid space can be generated, ref_alpha and ref_beta are set to zero - * (which means 'use auto lnors'). - */ -void BKE_lnor_space_define(MLoopNorSpace *lnor_space, - const float lnor[3], - float vec_ref[3], - float vec_other[3], - BLI_Stack *edge_vectors) -{ - const float pi2 = (float)M_PI * 2.0f; - float tvec[3], dtp; - const float dtp_ref = dot_v3v3(vec_ref, lnor); - const float dtp_other = dot_v3v3(vec_other, lnor); - - if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD || - fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) { - /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, - * tag it as invalid and abort. */ - lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; - - if (edge_vectors) { - BLI_stack_clear(edge_vectors); - } - return; - } - - copy_v3_v3(lnor_space->vec_lnor, lnor); - - /* Compute ref alpha, average angle of all available edge vectors to lnor. */ - if (edge_vectors) { - float alpha = 0.0f; - int nbr = 0; - while (!BLI_stack_is_empty(edge_vectors)) { - const float *vec = (const float *)BLI_stack_peek(edge_vectors); - alpha += saacosf(dot_v3v3(vec, lnor)); - BLI_stack_discard(edge_vectors); - nbr++; - } - /* NOTE: In theory, this could be 'nbr > 2', - * but there is one case where we only have two edges for two loops: - * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). - */ - BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */ - lnor_space->ref_alpha = alpha / (float)nbr; - } - else { - lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + - saacosf(dot_v3v3(vec_other, lnor))) / - 2.0f; - } - - /* Project vec_ref on lnor's ortho plane. */ - mul_v3_v3fl(tvec, lnor, dtp_ref); - sub_v3_v3(vec_ref, tvec); - normalize_v3_v3(lnor_space->vec_ref, vec_ref); - - cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref); - normalize_v3_v3(lnor_space->vec_ortho, tvec); - - /* Project vec_other on lnor's ortho plane. */ - mul_v3_v3fl(tvec, lnor, dtp_other); - sub_v3_v3(vec_other, tvec); - normalize_v3(vec_other); - - /* Beta is angle between ref_vec and other_vec, around lnor. */ - dtp = dot_v3v3(lnor_space->vec_ref, vec_other); - if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) { - const float beta = saacos(dtp); - lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; - } - else { - lnor_space->ref_beta = pi2; - } -} - -/** - * Add a new given loop to given lnor_space. - * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct - * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in - * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a - * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the - * linked list of loops in the fan. - */ -void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, - MLoopNorSpace *lnor_space, - const int ml_index, - void *bm_loop, - const bool is_single) -{ - BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == nullptr) || - (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != nullptr)); - - lnors_spacearr->lspacearr[ml_index] = lnor_space; - if (bm_loop == nullptr) { - bm_loop = POINTER_FROM_INT(ml_index); - } - if (is_single) { - BLI_assert(lnor_space->loops == nullptr); - lnor_space->flags |= MLNOR_SPACE_IS_SINGLE; - lnor_space->loops = (LinkNode *)bm_loop; - } - else { - BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0); - BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]); - } -} - -MINLINE float unit_short_to_float(const short val) -{ - return (float)val / (float)SHRT_MAX; -} - -MINLINE short unit_float_to_short(const float val) -{ - /* Rounding... */ - return (short)floorf(val * (float)SHRT_MAX + 0.5f); -} - -void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, - const short clnor_data[2], - float r_custom_lnor[3]) -{ - /* NOP custom normal data or invalid lnor space, return. */ - if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { - copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor); - return; - } - - { - /* TODO: Check whether using #sincosf() gives any noticeable benefit - * (could not even get it working under linux though)! */ - const float pi2 = (float)(M_PI * 2.0); - const float alphafac = unit_short_to_float(clnor_data[0]); - const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * - alphafac; - const float betafac = unit_short_to_float(clnor_data[1]); - - mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha)); - - if (betafac == 0.0f) { - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); - } - else { - const float sinalpha = sinf(alpha); - const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * - betafac; - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); - } - } -} - -void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, - const float custom_lnor[3], - short r_clnor_data[2]) -{ - /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). - */ - if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) { - r_clnor_data[0] = r_clnor_data[1] = 0; - return; - } - - { - const float pi2 = (float)(M_PI * 2.0); - const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor); - float vec[3], cos_beta; - float alpha; - - alpha = saacosf(cos_alpha); - if (alpha > lnor_space->ref_alpha) { - /* Note we could stick to [0, pi] range here, - * but makes decoding more complex, not worth it. */ - r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); - } - else { - r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); - } - - /* Project custom lnor on (vec_ref, vec_ortho) plane. */ - mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha); - add_v3_v3(vec, custom_lnor); - normalize_v3(vec); - - cos_beta = dot_v3v3(lnor_space->vec_ref, vec); - - if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { - float beta = saacosf(cos_beta); - if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { - beta = pi2 - beta; - } - - if (beta > lnor_space->ref_beta) { - r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); - } - else { - r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); - } - } - else { - r_clnor_data[1] = 0; - } - } -} - -#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024 - -struct LoopSplitTaskData { - /* Specific to each instance (each task). */ - - /** We have to create those outside of tasks, since #MemArena is not thread-safe. */ - MLoopNorSpace *lnor_space; - float (*lnor)[3]; - const MLoop *ml_curr; - const MLoop *ml_prev; - int ml_curr_index; - int ml_prev_index; - /** Also used a flag to switch between single or fan process! */ - const int *e2l_prev; - int mp_index; - - /** This one is special, it's owned and managed by worker tasks, - * avoid to have to create it for each fan! */ - BLI_Stack *edge_vectors; - - char pad_c; -}; - -struct LoopSplitTaskDataCommon { - /* Read/write. - * Note we do not need to protect it, though, since two different tasks will *always* affect - * different elements in the arrays. */ - MLoopNorSpaceArray *lnors_spacearr; - float (*loopnors)[3]; - short (*clnors_data)[2]; - - /* Read-only. */ - const MVert *mverts; - const MEdge *medges; - const MLoop *mloops; - const MPoly *mpolys; - int (*edge_to_loops)[2]; - int *loop_to_poly; - const float (*polynors)[3]; - - int numEdges; - int numLoops; - int numPolys; -}; - -#define INDEX_UNSET INT_MIN -#define INDEX_INVALID -1 -/* See comment about edge_to_loops below. */ -#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)) - -static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, - const bool check_angle, - const float split_angle, - const bool do_sharp_edges_tag) -{ - const MVert *mverts = data->mverts; - const MEdge *medges = data->medges; - const MLoop *mloops = data->mloops; - - const MPoly *mpolys = data->mpolys; - - const int numEdges = data->numEdges; - const int numPolys = data->numPolys; - - float(*loopnors)[3] = data->loopnors; /* NOTE: loopnors may be nullptr here. */ - const float(*polynors)[3] = data->polynors; - - int(*edge_to_loops)[2] = data->edge_to_loops; - int *loop_to_poly = data->loop_to_poly; - - BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : nullptr; - - const MPoly *mp; - int mp_index; - - const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; - - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - const MLoop *ml_curr; - int *e2l; - int ml_curr_index = mp->loopstart; - const int ml_last_index = (ml_curr_index + mp->totloop) - 1; - - ml_curr = &mloops[ml_curr_index]; - - for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { - e2l = edge_to_loops[ml_curr->e]; - - loop_to_poly[ml_curr_index] = mp_index; - - /* Pre-populate all loop normals as if their verts were all-smooth, - * this way we don't have to compute those later! - */ - if (loopnors) { - normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no); - } - - /* Check whether current edge might be smooth or sharp */ - if ((e2l[0] | e2l[1]) == 0) { - /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ - e2l[0] = ml_curr_index; - /* We have to check this here too, else we might miss some flat faces!!! */ - e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; - } - else if (e2l[1] == INDEX_UNSET) { - const bool is_angle_sharp = (check_angle && - dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < - split_angle_cos); - - /* Second loop using this edge, time to test its sharpness. - * An edge is sharp if it is tagged as such, or its face is not smooth, - * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the - * same vertex, or angle between both its polys' normals is above split_angle value. - */ - if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || - ml_curr->v == mloops[e2l[0]].v || is_angle_sharp) { - /* NOTE: we are sure that loop != 0 here ;). */ - e2l[1] = INDEX_INVALID; - - /* We want to avoid tagging edges as sharp when it is already defined as such by - * other causes than angle threshold... */ - if (do_sharp_edges_tag && is_angle_sharp) { - BLI_BITMAP_SET(sharp_edges, ml_curr->e, true); - } - } - else { - e2l[1] = ml_curr_index; - } - } - else if (!IS_EDGE_SHARP(e2l)) { - /* More than two loops using this edge, tag as sharp if not yet done. */ - e2l[1] = INDEX_INVALID; - - /* We want to avoid tagging edges as sharp when it is already defined as such by - * other causes than angle threshold... */ - if (do_sharp_edges_tag) { - BLI_BITMAP_SET(sharp_edges, ml_curr->e, false); - } - } - /* Else, edge is already 'disqualified' (i.e. sharp)! */ - } - } - - /* If requested, do actual tagging of edges as sharp in another loop. */ - if (do_sharp_edges_tag) { - MEdge *me; - int me_index; - for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) { - if (BLI_BITMAP_TEST(sharp_edges, me_index)) { - me->flag |= ME_SHARP; - } - } - - MEM_freeN(sharp_edges); - } -} - -/** - * Define sharp edges as needed to mimic 'autosmooth' from angle threshold. - * - * Used when defining an empty custom loop normals data layer, - * to keep same shading as with auto-smooth! - */ -void BKE_edges_sharp_from_angle_set(const struct MVert *mverts, - const int UNUSED(numVerts), - struct MEdge *medges, - const int numEdges, - struct MLoop *mloops, - const int numLoops, - struct MPoly *mpolys, - const float (*polynors)[3], - const int numPolys, - const float split_angle) -{ - if (split_angle >= (float)M_PI) { - /* Nothing to do! */ - return; - } - - /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */ - int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN( - (size_t)numEdges, sizeof(*edge_to_loops), __func__); - - /* Simple mapping from a loop to its polygon index. */ - int *loop_to_poly = (int *)MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); - - LoopSplitTaskDataCommon common_data = {}; - common_data.mverts = mverts; - common_data.medges = medges; - common_data.mloops = mloops; - common_data.mpolys = mpolys; - common_data.edge_to_loops = edge_to_loops; - common_data.loop_to_poly = loop_to_poly; - common_data.polynors = polynors; - common_data.numEdges = numEdges; - common_data.numPolys = numPolys; - - mesh_edges_sharp_tag(&common_data, true, split_angle, true); - - MEM_freeN(edge_to_loops); - MEM_freeN(loop_to_poly); -} - -void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, - const MPoly *mpolys, - const int *loop_to_poly, - const int *e2lfan_curr, - const uint mv_pivot_index, - const MLoop **r_mlfan_curr, - int *r_mlfan_curr_index, - int *r_mlfan_vert_index, - int *r_mpfan_curr_index) -{ - const MLoop *mlfan_next; - const MPoly *mpfan_next; - - /* Warning! This is rather complex! - * We have to find our next edge around the vertex (fan mode). - * First we find the next loop, which is either previous or next to mlfan_curr_index, depending - * whether both loops using current edge are in the same direction or not, and whether - * mlfan_curr_index actually uses the vertex we are fanning around! - * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one - * (i.e. not the future mlfan_curr)... - */ - *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0]; - *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index]; - - BLI_assert(*r_mlfan_curr_index >= 0); - BLI_assert(*r_mpfan_curr_index >= 0); - - mlfan_next = &mloops[*r_mlfan_curr_index]; - mpfan_next = &mpolys[*r_mpfan_curr_index]; - if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) || - ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index)) { - /* We need the previous loop, but current one is our vertex's loop. */ - *r_mlfan_vert_index = *r_mlfan_curr_index; - if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) { - *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1; - } - } - else { - /* We need the next loop, which is also our vertex's loop. */ - if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) { - *r_mlfan_curr_index = mpfan_next->loopstart; - } - *r_mlfan_vert_index = *r_mlfan_curr_index; - } - *r_mlfan_curr = &mloops[*r_mlfan_curr_index]; - /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */ -} - -static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) -{ - MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - const short(*clnors_data)[2] = common_data->clnors_data; - - const MVert *mverts = common_data->mverts; - const MEdge *medges = common_data->medges; - const float(*polynors)[3] = common_data->polynors; - - MLoopNorSpace *lnor_space = data->lnor_space; - float(*lnor)[3] = data->lnor; - const MLoop *ml_curr = data->ml_curr; - const MLoop *ml_prev = data->ml_prev; - const int ml_curr_index = data->ml_curr_index; -#if 0 /* Not needed for 'single' loop. */ - const int ml_prev_index = data->ml_prev_index; - const int *e2l_prev = data->e2l_prev; -#endif - const int mp_index = data->mp_index; - - /* Simple case (both edges around that vertex are sharp in current polygon), - * this loop just takes its poly normal. - */ - copy_v3_v3(*lnor, polynors[mp_index]); - -#if 0 - printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", - ml_curr_index, - ml_curr->e, - ml_curr->v, - mp_index); -#endif - - /* If needed, generate this (simple!) lnor space. */ - if (lnors_spacearr) { - float vec_curr[3], vec_prev[3]; - - const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const MVert *mv_pivot = &mverts[mv_pivot_index]; - const MEdge *me_curr = &medges[ml_curr->e]; - const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : - &mverts[me_curr->v1]; - const MEdge *me_prev = &medges[ml_prev->e]; - const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : - &mverts[me_prev->v1]; - - sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); - normalize_v3(vec_curr); - sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co); - normalize_v3(vec_prev); - - BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, nullptr); - /* We know there is only one loop in this space, - * no need to create a linklist in this case... */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true); - - if (clnors_data) { - BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor); - } - } -} - -static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) -{ - MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - float(*loopnors)[3] = common_data->loopnors; - short(*clnors_data)[2] = common_data->clnors_data; - - const MVert *mverts = common_data->mverts; - const MEdge *medges = common_data->medges; - const MLoop *mloops = common_data->mloops; - const MPoly *mpolys = common_data->mpolys; - const int(*edge_to_loops)[2] = common_data->edge_to_loops; - const int *loop_to_poly = common_data->loop_to_poly; - const float(*polynors)[3] = common_data->polynors; - - MLoopNorSpace *lnor_space = data->lnor_space; -#if 0 /* Not needed for 'fan' loops. */ - float(*lnor)[3] = data->lnor; -#endif - const MLoop *ml_curr = data->ml_curr; - const MLoop *ml_prev = data->ml_prev; - const int ml_curr_index = data->ml_curr_index; - const int ml_prev_index = data->ml_prev_index; - const int mp_index = data->mp_index; - const int *e2l_prev = data->e2l_prev; - - BLI_Stack *edge_vectors = data->edge_vectors; - - /* Gah... We have to fan around current vertex, until we find the other non-smooth edge, - * and accumulate face normals into the vertex! - * Note in case this vertex has only one sharp edges, this is a waste because the normal is the - * same as the vertex normal, but I do not see any easy way to detect that (would need to count - * number of sharp edges per vertex, I doubt the additional memory usage would be worth it, - * especially as it should not be a common case in real-life meshes anyway). - */ - const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const MVert *mv_pivot = &mverts[mv_pivot_index]; - - /* ml_curr would be mlfan_prev if we needed that one. */ - const MEdge *me_org = &medges[ml_curr->e]; - - const int *e2lfan_curr; - float vec_curr[3], vec_prev[3], vec_org[3]; - const MLoop *mlfan_curr; - float lnor[3] = {0.0f, 0.0f, 0.0f}; - /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ - int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; - - /* We validate clnors data on the fly - cheapest way to do! */ - int clnors_avg[2] = {0, 0}; - short(*clnor_ref)[2] = nullptr; - int clnors_nbr = 0; - bool clnors_invalid = false; - - /* Temp loop normal stack. */ - BLI_SMALLSTACK_DECLARE(normal, float *); - /* Temp clnors stack. */ - BLI_SMALLSTACK_DECLARE(clnors, short *); - - e2lfan_curr = e2l_prev; - mlfan_curr = ml_prev; - mlfan_curr_index = ml_prev_index; - mlfan_vert_index = ml_curr_index; - mpfan_curr_index = mp_index; - - BLI_assert(mlfan_curr_index >= 0); - BLI_assert(mlfan_vert_index >= 0); - BLI_assert(mpfan_curr_index >= 0); - - /* Only need to compute previous edge's vector once, then we can just reuse old current one! */ - { - const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1]; - - sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co); - normalize_v3(vec_org); - copy_v3_v3(vec_prev, vec_org); - - if (lnors_spacearr) { - BLI_stack_push(edge_vectors, vec_org); - } - } - - // printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); - - while (true) { - const MEdge *me_curr = &medges[mlfan_curr->e]; - /* Compute edge vectors. - * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing - * them twice (or more) here. However, time gained is not worth memory and time lost, - * given the fact that this code should not be called that much in real-life meshes... - */ - { - const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : - &mverts[me_curr->v1]; - - sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co); - normalize_v3(vec_curr); - } - - // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); - - { - /* Code similar to accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. */ - const float fac = saacos(dot_v3v3(vec_curr, vec_prev)); - /* Accumulate */ - madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); - - if (clnors_data) { - /* Accumulate all clnors, if they are not all equal we have to fix that! */ - short(*clnor)[2] = &clnors_data[mlfan_vert_index]; - if (clnors_nbr) { - clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]); - } - else { - clnor_ref = clnor; - } - clnors_avg[0] += (*clnor)[0]; - clnors_avg[1] += (*clnor)[1]; - clnors_nbr++; - /* We store here a pointer to all custom lnors processed. */ - BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor); - } - } - - /* We store here a pointer to all loop-normals processed. */ - BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index])); - - if (lnors_spacearr) { - /* Assign current lnor space to current 'vertex' loop. */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, nullptr, false); - if (me_curr != me_org) { - /* We store here all edges-normalized vectors processed. */ - BLI_stack_push(edge_vectors, vec_curr); - } - } - - if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) { - /* Current edge is sharp and we have finished with this fan of faces around this vert, - * or this vert is smooth, and we have completed a full turn around it. */ - // printf("FAN: Finished!\n"); - break; - } - - copy_v3_v3(vec_prev, vec_curr); - - /* Find next loop of the smooth fan. */ - BKE_mesh_loop_manifold_fan_around_vert_next(mloops, - mpolys, - loop_to_poly, - e2lfan_curr, - mv_pivot_index, - &mlfan_curr, - &mlfan_curr_index, - &mlfan_vert_index, - &mpfan_curr_index); - - e2lfan_curr = edge_to_loops[mlfan_curr->e]; - } - - { - float lnor_len = normalize_v3(lnor); - - /* If we are generating lnor spacearr, we can now define the one for this fan, - * and optionally compute final lnor from custom data too! - */ - if (lnors_spacearr) { - if (UNLIKELY(lnor_len == 0.0f)) { - /* Use vertex normal as fallback! */ - copy_v3_v3(lnor, loopnors[mlfan_vert_index]); - lnor_len = 1.0f; - } - - BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors); - - if (clnors_data) { - if (clnors_invalid) { - short *clnor; - - clnors_avg[0] /= clnors_nbr; - clnors_avg[1] /= clnors_nbr; - /* Fix/update all clnors of this fan with computed average value. */ - if (G.debug & G_DEBUG) { - printf("Invalid clnors in this fan!\n"); - } - while ((clnor = (short *)BLI_SMALLSTACK_POP(clnors))) { - // print_v2("org clnor", clnor); - clnor[0] = (short)clnors_avg[0]; - clnor[1] = (short)clnors_avg[1]; - } - // print_v2("new clnors", clnors_avg); - } - /* Extra bonus: since small-stack is local to this function, - * no more need to empty it at all cost! */ - - BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); - } - } - - /* In case we get a zero normal here, just use vertex normal already set! */ - if (LIKELY(lnor_len != 0.0f)) { - /* Copy back the final computed normal into all related loop-normals. */ - float *nor; - - while ((nor = (float *)BLI_SMALLSTACK_POP(normal))) { - copy_v3_v3(nor, lnor); - } - } - /* Extra bonus: since small-stack is local to this function, - * no more need to empty it at all cost! */ - } -} - -static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data, - LoopSplitTaskData *data, - BLI_Stack *edge_vectors) -{ - BLI_assert(data->ml_curr); - if (data->e2l_prev) { - BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors)); - data->edge_vectors = edge_vectors; - split_loop_nor_fan_do(common_data, data); - } - else { - /* No need for edge_vectors for 'single' case! */ - split_loop_nor_single_do(common_data, data); - } -} - -static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) -{ - LoopSplitTaskDataCommon *common_data = (LoopSplitTaskDataCommon *)BLI_task_pool_user_data(pool); - LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata; - - /* Temp edge vectors stack, only used when computing lnor spacearr. */ - BLI_Stack *edge_vectors = common_data->lnors_spacearr ? - BLI_stack_new(sizeof(float[3]), __func__) : - nullptr; - -#ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(loop_split_worker); -#endif - - for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) { - /* A nullptr ml_curr is used to tag ended data! */ - if (data->ml_curr == nullptr) { - break; - } - - loop_split_worker_do(common_data, data, edge_vectors); - } - - if (edge_vectors) { - BLI_stack_free(edge_vectors); - } - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(loop_split_worker); -#endif -} - -/** - * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not. - * Needed because cyclic smooth fans have no obvious 'entry point', - * and yet we need to walk them once, and only once. - */ -static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, - const MPoly *mpolys, - const int (*edge_to_loops)[2], - const int *loop_to_poly, - const int *e2l_prev, - BLI_bitmap *skip_loops, - const MLoop *ml_curr, - const MLoop *ml_prev, - const int ml_curr_index, - const int ml_prev_index, - const int mp_curr_index) -{ - const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ - const int *e2lfan_curr; - const MLoop *mlfan_curr; - /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ - int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; - - e2lfan_curr = e2l_prev; - if (IS_EDGE_SHARP(e2lfan_curr)) { - /* Sharp loop, so not a cyclic smooth fan... */ - return false; - } - - mlfan_curr = ml_prev; - mlfan_curr_index = ml_prev_index; - mlfan_vert_index = ml_curr_index; - mpfan_curr_index = mp_curr_index; - - BLI_assert(mlfan_curr_index >= 0); - BLI_assert(mlfan_vert_index >= 0); - BLI_assert(mpfan_curr_index >= 0); - - BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)); - BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index); - - while (true) { - /* Find next loop of the smooth fan. */ - BKE_mesh_loop_manifold_fan_around_vert_next(mloops, - mpolys, - loop_to_poly, - e2lfan_curr, - mv_pivot_index, - &mlfan_curr, - &mlfan_curr_index, - &mlfan_vert_index, - &mpfan_curr_index); - - e2lfan_curr = edge_to_loops[mlfan_curr->e]; - - if (IS_EDGE_SHARP(e2lfan_curr)) { - /* Sharp loop/edge, so not a cyclic smooth fan... */ - return false; - } - /* Smooth loop/edge... */ - if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) { - if (mlfan_vert_index == ml_curr_index) { - /* We walked around a whole cyclic smooth fan without finding any already-processed loop, - * means we can use initial ml_curr/ml_prev edge as start for this smooth fan. */ - return true; - } - /* ... already checked in some previous looping, we can abort. */ - return false; - } - - /* ... we can skip it in future, and keep checking the smooth fan. */ - BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index); - } -} - -static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data) -{ - MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; - float(*loopnors)[3] = common_data->loopnors; - - const MLoop *mloops = common_data->mloops; - const MPoly *mpolys = common_data->mpolys; - const int *loop_to_poly = common_data->loop_to_poly; - const int(*edge_to_loops)[2] = common_data->edge_to_loops; - const int numLoops = common_data->numLoops; - const int numPolys = common_data->numPolys; - - const MPoly *mp; - int mp_index; - - const MLoop *ml_curr; - const MLoop *ml_prev; - int ml_curr_index; - int ml_prev_index; - - BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__); - - LoopSplitTaskData *data_buff = nullptr; - int data_idx = 0; - - /* Temp edge vectors stack, only used when computing lnor spacearr - * (and we are not multi-threading). */ - BLI_Stack *edge_vectors = nullptr; - -#ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(loop_split_generator); -#endif - - if (!pool) { - if (lnors_spacearr) { - edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); - } - } - - /* We now know edges that can be smoothed (with their vector, and their two loops), - * and edges that will be hard! Now, time to generate the normals. - */ - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - float(*lnors)[3]; - const int ml_last_index = (mp->loopstart + mp->totloop) - 1; - ml_curr_index = mp->loopstart; - ml_prev_index = ml_last_index; - - ml_curr = &mloops[ml_curr_index]; - ml_prev = &mloops[ml_prev_index]; - lnors = &loopnors[ml_curr_index]; - - for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) { - const int *e2l_curr = edge_to_loops[ml_curr->e]; - const int *e2l_prev = edge_to_loops[ml_prev->e]; - -#if 0 - printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...", - ml_curr_index, - ml_curr->e, - ml_curr->v, - IS_EDGE_SHARP(e2l_curr), - BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index)); -#endif - - /* A smooth edge, we have to check for cyclic smooth fan case. - * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge - * as 'entry point', otherwise we can skip it. */ - - /* NOTE: In theory, we could make #loop_split_generator_check_cyclic_smooth_fan() store - * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around - * the vert during actual computation of `clnor` & `clnorspace`. - * However, this would complicate the code, add more memory usage, and despite its logical - * complexity, #loop_manifold_fan_around_vert_next() is quite cheap in term of CPU cycles, - * so really think it's not worth it. */ - if (!IS_EDGE_SHARP(e2l_curr) && (BLI_BITMAP_TEST(skip_loops, ml_curr_index) || - !loop_split_generator_check_cyclic_smooth_fan(mloops, - mpolys, - edge_to_loops, - loop_to_poly, - e2l_prev, - skip_loops, - ml_curr, - ml_prev, - ml_curr_index, - ml_prev_index, - mp_index))) { - // printf("SKIPPING!\n"); - } - else { - LoopSplitTaskData *data, data_local; - - // printf("PROCESSING!\n"); - - if (pool) { - if (data_idx == 0) { - data_buff = (LoopSplitTaskData *)MEM_calloc_arrayN( - LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__); - } - data = &data_buff[data_idx]; - } - else { - data = &data_local; - memset(data, 0, sizeof(*data)); - } - - if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) { - data->lnor = lnors; - data->ml_curr = ml_curr; - data->ml_prev = ml_prev; - data->ml_curr_index = ml_curr_index; -#if 0 /* Not needed for 'single' loop. */ - data->ml_prev_index = ml_prev_index; - data->e2l_prev = nullptr; /* Tag as 'single' task. */ -#endif - data->mp_index = mp_index; - if (lnors_spacearr) { - data->lnor_space = BKE_lnor_space_create(lnors_spacearr); - } - } - /* We *do not need* to check/tag loops as already computed! - * Due to the fact a loop only links to one of its two edges, - * a same fan *will never be walked more than once!* - * Since we consider edges having neighbor polys with inverted - * (flipped) normals as sharp, we are sure that no fan will be skipped, - * even only considering the case (sharp curr_edge, smooth prev_edge), - * and not the alternative (smooth curr_edge, sharp prev_edge). - * All this due/thanks to link between normals and loop ordering (i.e. winding). - */ - else { -#if 0 /* Not needed for 'fan' loops. */ - data->lnor = lnors; -#endif - data->ml_curr = ml_curr; - data->ml_prev = ml_prev; - data->ml_curr_index = ml_curr_index; - data->ml_prev_index = ml_prev_index; - data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */ - data->mp_index = mp_index; - if (lnors_spacearr) { - data->lnor_space = BKE_lnor_space_create(lnors_spacearr); - } - } - - if (pool) { - data_idx++; - if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) { - BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr); - data_idx = 0; - } - } - else { - loop_split_worker_do(common_data, data, edge_vectors); - } - } - - ml_prev = ml_curr; - ml_prev_index = ml_curr_index; - } - } - - /* Last block of data... Since it is calloc'ed and we use first nullptr item as stopper, - * everything is fine. */ - if (pool && data_idx) { - BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr); - } - - if (edge_vectors) { - BLI_stack_free(edge_vectors); - } - MEM_freeN(skip_loops); - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(loop_split_generator); -#endif -} - -/** - * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). - * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry - * (splitting edges). - */ -void BKE_mesh_normals_loop_split(const MVert *mverts, - const int UNUSED(numVerts), - MEdge *medges, - const int numEdges, - MLoop *mloops, - float (*r_loopnors)[3], - const int numLoops, - MPoly *mpolys, - const float (*polynors)[3], - const int numPolys, - const bool use_split_normals, - const float split_angle, - MLoopNorSpaceArray *r_lnors_spacearr, - short (*clnors_data)[2], - int *r_loop_to_poly) -{ - /* For now this is not supported. - * If we do not use split normals, we do not generate anything fancy! */ - BLI_assert(use_split_normals || !(r_lnors_spacearr)); - - if (!use_split_normals) { - /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple! - * Note this is done here to keep some logic and consistency in this quite complex code, - * since we may want to use lnors even when mesh's 'autosmooth' is disabled - * (see e.g. mesh mapping code). - * As usual, we could handle that on case-by-case basis, - * but simpler to keep it well confined here. - */ - int mp_index; - - for (mp_index = 0; mp_index < numPolys; mp_index++) { - MPoly *mp = &mpolys[mp_index]; - int ml_index = mp->loopstart; - const int ml_index_end = ml_index + mp->totloop; - const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0); - - for (; ml_index < ml_index_end; ml_index++) { - if (r_loop_to_poly) { - r_loop_to_poly[ml_index] = mp_index; - } - if (is_poly_flat) { - copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]); - } - else { - normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no); - } - } - } - return; - } - - /** - * Mapping edge -> loops. - * If that edge is used by more than two loops (polys), - * it is always sharp (and tagged as such, see below). - * We also use the second loop index as a kind of flag: - * - * - smooth edge: > 0. - * - sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET). - * - unset: INDEX_UNSET. - * - * Note that currently we only have two values for second loop of sharp edges. - * However, if needed, we can store the negated value of loop index instead of INDEX_INVALID - * to retrieve the real value later in code). - * Note also that loose edges always have both values set to 0! */ - int(*edge_to_loops)[2] = (int(*)[2])MEM_calloc_arrayN( - (size_t)numEdges, sizeof(*edge_to_loops), __func__); - - /* Simple mapping from a loop to its polygon index. */ - int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : - (int *)MEM_malloc_arrayN( - (size_t)numLoops, sizeof(*loop_to_poly), __func__); - - /* When using custom loop normals, disable the angle feature! */ - const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == nullptr); - - MLoopNorSpaceArray _lnors_spacearr = {nullptr}; - -#ifdef DEBUG_TIME - TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split); -#endif - - if (!r_lnors_spacearr && clnors_data) { - /* We need to compute lnor spacearr if some custom lnor data are given to us! */ - r_lnors_spacearr = &_lnors_spacearr; - } - if (r_lnors_spacearr) { - BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX); - } - - /* Init data common to all tasks. */ - LoopSplitTaskDataCommon common_data; - common_data.lnors_spacearr = r_lnors_spacearr; - common_data.loopnors = r_loopnors; - common_data.clnors_data = clnors_data; - common_data.mverts = mverts; - common_data.medges = medges; - common_data.mloops = mloops; - common_data.mpolys = mpolys; - common_data.edge_to_loops = edge_to_loops; - common_data.loop_to_poly = loop_to_poly; - common_data.polynors = polynors; - common_data.numEdges = numEdges; - common_data.numLoops = numLoops; - common_data.numPolys = numPolys; - - /* This first loop check which edges are actually smooth, and compute edge vectors. */ - mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false); - - if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { - /* Not enough loops to be worth the whole threading overhead... */ - loop_split_generator(nullptr, &common_data); - } - else { - TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH); - - loop_split_generator(task_pool, &common_data); - - BLI_task_pool_work_and_wait(task_pool); - - BLI_task_pool_free(task_pool); - } - - MEM_freeN(edge_to_loops); - if (!r_loop_to_poly) { - MEM_freeN(loop_to_poly); - } - - if (r_lnors_spacearr) { - if (r_lnors_spacearr == &_lnors_spacearr) { - BKE_lnor_spacearr_free(r_lnors_spacearr); - } - } - -#ifdef DEBUG_TIME - TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split); -#endif -} - -#undef INDEX_UNSET -#undef INDEX_INVALID -#undef IS_EDGE_SHARP - -/** - * Compute internal representation of given custom normals (as an array of float[2]). - * It also makes sure the mesh matches those custom normals, by setting sharp edges flag as needed - * to get a same custom lnor for all loops sharing a same smooth fan. - * If use_vertices if true, r_custom_loopnors is assumed to be per-vertex, not per-loop - * (this allows to set whole vert's normals at once, useful in some cases). - * r_custom_loopnors is expected to have normalized normals, or zero ones, - * in which case they will be replaced by default loop/vertex normal. - */ -static void mesh_normals_loop_custom_set(const MVert *mverts, - const int numVerts, - MEdge *medges, - const int numEdges, - MLoop *mloops, - float (*r_custom_loopnors)[3], - const int numLoops, - MPoly *mpolys, - const float (*polynors)[3], - const int numPolys, - short (*r_clnors_data)[2], - const bool use_vertices) -{ - /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling - * that feature too, would probably be more efficient in absolute. - * However, this function *is not* performance-critical, since it is mostly expected to be called - * by io addons when importing custom normals, and modifier - * (and perhaps from some editing tools later?). - * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice! - */ - MLoopNorSpaceArray lnors_spacearr = {nullptr}; - BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__); - float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__); - int *loop_to_poly = (int *)MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__); - /* In this case we always consider split nors as ON, - * and do not want to use angle to define smooth fans! */ - const bool use_split_normals = true; - const float split_angle = (float)M_PI; - - BLI_SMALLSTACK_DECLARE(clnors_data, short *); - - /* Compute current lnor spacearr. */ - BKE_mesh_normals_loop_split(mverts, - numVerts, - medges, - numEdges, - mloops, - lnors, - numLoops, - mpolys, - polynors, - numPolys, - use_split_normals, - split_angle, - &lnors_spacearr, - nullptr, - loop_to_poly); - - /* Set all given zero vectors to their default value. */ - if (use_vertices) { - for (int i = 0; i < numVerts; i++) { - if (is_zero_v3(r_custom_loopnors[i])) { - normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no); - } - } - } - else { - for (int i = 0; i < numLoops; i++) { - if (is_zero_v3(r_custom_loopnors[i])) { - copy_v3_v3(r_custom_loopnors[i], lnors[i]); - } - } - } - - BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX); - - /* Now, check each current smooth fan (one lnor space per smooth fan!), - * and if all its matching custom lnors are not (enough) equal, add sharp edges as needed. - * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans - * matching given custom lnors. - * Note this code *will never* unsharp edges! And quite obviously, - * when we set custom normals per vertices, running this is absolutely useless. - */ - if (!use_vertices) { - for (int i = 0; i < numLoops; i++) { - if (!lnors_spacearr.lspacearr[i]) { - /* This should not happen in theory, but in some rare case (probably ugly geometry) - * we can get some nullptr loopspacearr at this point. :/ - * Maybe we should set those loops' edges as sharp? - */ - BLI_BITMAP_ENABLE(done_loops, i); - if (G.debug & G_DEBUG) { - printf("WARNING! Getting invalid nullptr loop space for loop %d!\n", i); - } - continue; - } - - if (!BLI_BITMAP_TEST(done_loops, i)) { - /* Notes: - * * In case of mono-loop smooth fan, we have nothing to do. - * * Loops in this linklist are ordered (in reversed order compared to how they were - * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). - * Which means if we find a mismatching clnor, - * we know all remaining loops will have to be in a new, different smooth fan/lnor space. - * * In smooth fan case, we compare each clnor against a ref one, - * to avoid small differences adding up into a real big one in the end! - */ - if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { - BLI_BITMAP_ENABLE(done_loops, i); - continue; - } - - LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; - MLoop *prev_ml = nullptr; - const float *org_nor = nullptr; - - while (loops) { - const int lidx = POINTER_AS_INT(loops->link); - MLoop *ml = &mloops[lidx]; - const int nidx = lidx; - float *nor = r_custom_loopnors[nidx]; - - if (!org_nor) { - org_nor = nor; - } - else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { - /* Current normal differs too much from org one, we have to tag the edge between - * previous loop's face and current's one as sharp. - * We know those two loops do not point to the same edge, - * since we do not allow reversed winding in a same smooth fan. - */ - const MPoly *mp = &mpolys[loop_to_poly[lidx]]; - const MLoop *mlp = - &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; - medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; - - org_nor = nor; - } - - prev_ml = ml; - loops = loops->next; - BLI_BITMAP_ENABLE(done_loops, lidx); - } - - /* We also have to check between last and first loops, - * otherwise we may miss some sharp edges here! - * This is just a simplified version of above while loop. - * See T45984. */ - loops = lnors_spacearr.lspacearr[i]->loops; - if (loops && org_nor) { - const int lidx = POINTER_AS_INT(loops->link); - MLoop *ml = &mloops[lidx]; - const int nidx = lidx; - float *nor = r_custom_loopnors[nidx]; - - if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { - const MPoly *mp = &mpolys[loop_to_poly[lidx]]; - const MLoop *mlp = - &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; - medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; - } - } - } - } - - /* And now, recompute our new auto lnors and lnor spacearr! */ - BKE_lnor_spacearr_clear(&lnors_spacearr); - BKE_mesh_normals_loop_split(mverts, - numVerts, - medges, - numEdges, - mloops, - lnors, - numLoops, - mpolys, - polynors, - numPolys, - use_split_normals, - split_angle, - &lnors_spacearr, - nullptr, - loop_to_poly); - } - else { - BLI_bitmap_set_all(done_loops, true, (size_t)numLoops); - } - - /* And we just have to convert plain object-space custom normals to our - * lnor space-encoded ones. */ - for (int i = 0; i < numLoops; i++) { - if (!lnors_spacearr.lspacearr[i]) { - BLI_BITMAP_DISABLE(done_loops, i); - if (G.debug & G_DEBUG) { - printf("WARNING! Still getting invalid nullptr loop space in second loop for loop %d!\n", - i); - } - continue; - } - - if (BLI_BITMAP_TEST_BOOL(done_loops, i)) { - /* Note we accumulate and average all custom normals in current smooth fan, - * to avoid getting different clnors data (tiny differences in plain custom normals can - * give rather huge differences in computed 2D factors). - */ - LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; - if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { - BLI_assert(POINTER_AS_INT(loops) == i); - const int nidx = use_vertices ? (int)mloops[i].v : i; - float *nor = r_custom_loopnors[nidx]; - - BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); - BLI_BITMAP_DISABLE(done_loops, i); - } - else { - int nbr_nors = 0; - float avg_nor[3]; - short clnor_data_tmp[2], *clnor_data; - - zero_v3(avg_nor); - while (loops) { - const int lidx = POINTER_AS_INT(loops->link); - const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; - float *nor = r_custom_loopnors[nidx]; - - nbr_nors++; - add_v3_v3(avg_nor, nor); - BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]); - - loops = loops->next; - BLI_BITMAP_DISABLE(done_loops, lidx); - } - - mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors); - BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp); - - while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) { - clnor_data[0] = clnor_data_tmp[0]; - clnor_data[1] = clnor_data_tmp[1]; - } - } - } - } - - MEM_freeN(lnors); - MEM_freeN(loop_to_poly); - MEM_freeN(done_loops); - BKE_lnor_spacearr_free(&lnors_spacearr); -} - -void BKE_mesh_normals_loop_custom_set(const MVert *mverts, - const int numVerts, - MEdge *medges, - const int numEdges, - MLoop *mloops, - float (*r_custom_loopnors)[3], - const int numLoops, - MPoly *mpolys, - const float (*polynors)[3], - const int numPolys, - short (*r_clnors_data)[2]) -{ - mesh_normals_loop_custom_set(mverts, - numVerts, - medges, - numEdges, - mloops, - r_custom_loopnors, - numLoops, - mpolys, - polynors, - numPolys, - r_clnors_data, - false); -} - -void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts, - float (*r_custom_vertnors)[3], - const int numVerts, - MEdge *medges, - const int numEdges, - MLoop *mloops, - const int numLoops, - MPoly *mpolys, - const float (*polynors)[3], - const int numPolys, - short (*r_clnors_data)[2]) -{ - mesh_normals_loop_custom_set(mverts, - numVerts, - medges, - numEdges, - mloops, - r_custom_vertnors, - numLoops, - mpolys, - polynors, - numPolys, - r_clnors_data, - true); -} - -static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices) -{ - short(*clnors)[2]; - const int numloops = mesh->totloop; - - clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); - if (clnors != nullptr) { - memset(clnors, 0, sizeof(*clnors) * (size_t)numloops); - } - else { - clnors = (short(*)[2])CustomData_add_layer( - &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops); - } - - float(*polynors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); - bool free_polynors = false; - if (polynors == nullptr) { - polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__); - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - polynors, - false); - free_polynors = true; - } - - mesh_normals_loop_custom_set(mesh->mvert, - mesh->totvert, - mesh->medge, - mesh->totedge, - mesh->mloop, - r_custom_nors, - mesh->totloop, - mesh->mpoly, - polynors, - mesh->totpoly, - clnors, - use_vertices); - - if (free_polynors) { - MEM_freeN(polynors); - } -} - -/** - * Higher level functions hiding most of the code needed around call to - * #BKE_mesh_normals_loop_custom_set(). - * - * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there - * with automatically computed vectors. - */ -void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3]) -{ - mesh_set_custom_normals(mesh, r_custom_loopnors, false); -} - -/** - * Higher level functions hiding most of the code needed around call to - * #BKE_mesh_normals_loop_custom_from_vertices_set(). - * - * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there - * with automatically computed vectors. - */ -void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3]) -{ - mesh_set_custom_normals(mesh, r_custom_vertnors, true); -} - -/** - * Computes average per-vertex normals from given custom loop normals. - * - * \param clnors: The computed custom loop normals. - * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals. - */ -void BKE_mesh_normals_loop_to_vertex(const int numVerts, - const MLoop *mloops, - const int numLoops, - const float (*clnors)[3], - float (*r_vert_clnors)[3]) -{ - int *vert_loops_nbr = (int *)MEM_calloc_arrayN( - (size_t)numVerts, sizeof(*vert_loops_nbr), __func__); - - copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f); - - int i; - const MLoop *ml; - for (i = 0, ml = mloops; i < numLoops; i++, ml++) { - const uint v = ml->v; - - add_v3_v3(r_vert_clnors[v], clnors[i]); - vert_loops_nbr[v]++; - } - - for (i = 0; i < numVerts; i++) { - mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]); - } - - MEM_freeN(vert_loops_nbr); -} - -#undef LNOR_SPACE_TRIGO_THRESHOLD - -/** \} */ -- cgit v1.2.3 From 1ef275963d1cfa257de184f38a2abb04a5df3ac7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 14:34:41 +1000 Subject: Cleanup: use C++ style comments for disabled code --- source/blender/blenkernel/intern/DerivedMesh.cc | 2 +- source/blender/blenkernel/intern/curve.c | 2 +- source/blender/blenkernel/intern/customdata.c | 2 +- source/blender/blenkernel/intern/image.c | 2 +- source/blender/blenkernel/intern/mask_rasterize.c | 4 +- source/blender/blenkernel/intern/mball.c | 2 +- source/blender/blenkernel/intern/mesh.c | 4 +- source/blender/blenkernel/intern/mesh_convert.c | 4 +- source/blender/blenkernel/intern/mesh_normals.cc | 4 +- source/blender/blenkernel/intern/ocean.c | 10 ++-- source/blender/blenkernel/intern/ocean_spectrum.c | 2 +- source/blender/blenkernel/intern/softbody.c | 4 +- source/blender/datatoc/datatoc.c | 2 +- source/blender/editors/gpencil/gpencil_utils.c | 2 +- source/blender/editors/interface/interface_align.c | 2 +- source/blender/editors/interface/interface_draw.c | 4 +- source/blender/editors/object/object_vgroup.c | 2 +- source/blender/editors/space_file/file_ops.c | 2 +- source/blender/editors/space_graph/graph_buttons.c | 2 +- .../blender/editors/space_outliner/outliner_edit.c | 2 +- source/blender/editors/transform/transform_mode.c | 4 +- .../editors/transform/transform_mode_edge_slide.c | 4 +- .../blender/imbuf/intern/openexr/openexr_api.cpp | 2 +- source/blender/io/collada/AnimationImporter.cpp | 2 +- source/blender/makesrna/intern/rna_access.c | 2 +- source/blender/makesrna/intern/rna_armature.c | 8 +-- source/blender/makesrna/intern/rna_mesh.c | 2 +- source/blender/makesrna/intern/rna_nodetree.c | 8 +-- source/blender/makesrna/intern/rna_particle.c | 10 ++-- source/blender/makesrna/intern/rna_speaker.c | 70 +++++++++++++++------- source/blender/makesrna/intern/rna_ui.c | 4 +- source/blender/makesrna/intern/rna_wm.c | 28 +++++---- source/blender/makesrna/intern/rna_wm_api.c | 2 +- source/blender/makesrna/intern/rna_wm_gizmo.c | 22 +++---- source/blender/makesrna/intern/rna_world.c | 2 +- source/blender/python/intern/bpy_rna.c | 2 +- source/blender/python/intern/bpy_rna_array.c | 2 +- .../blender/windowmanager/intern/wm_files_link.c | 4 +- 38 files changed, 132 insertions(+), 106 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index ba8cf8debe9..4480b0d34fc 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -360,7 +360,7 @@ void DM_init(DerivedMesh *dm, dm->needsFree = 1; dm->dirty = (DMDirtyFlag)0; - /* Don't use CustomData_reset(...); because we don't want to touch custom-data. */ + /* Don't use #CustomData_reset because we don't want to touch custom-data. */ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 49c81d793c3..db0ea71e233 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -638,7 +638,7 @@ void BKE_nurb_free(Nurb *nu) MEM_freeN(nu->knotsv); } nu->knotsv = NULL; - /* if (nu->trim.first) freeNurblist(&(nu->trim)); */ + // if (nu->trim.first) freeNurblist(&(nu->trim)); MEM_freeN(nu); } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index a9a8fd7410a..1a3200a9b6c 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -4246,7 +4246,7 @@ void CustomData_blend_write_prepare(CustomData *data, CustomDataLayer *layer = &data->layers[i]; if (layer->flag & CD_FLAG_NOCOPY) { /* Layers with this flag set are not written to file. */ data->totlayer--; - /* CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); */ + // CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); } else { if (UNLIKELY((size_t)j >= write_layers_size)) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f4ba1ff8b92..ba54858ba84 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1020,7 +1020,7 @@ Image *BKE_image_add_generated(Main *bmain, int view_id; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - /* STRNCPY(ima->filepath, name); */ /* don't do this, this writes in ain invalid filepath! */ + // STRNCPY(ima->filepath, name); /* don't do this, this writes in ain invalid filepath! */ ima->gen_x = width; ima->gen_y = height; ima->gen_type = gen_type; diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 8acc929a089..e04e5fceec6 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -292,10 +292,10 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather co_curr = diff_points[k_curr]; co_next = diff_points[k_next]; - /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */ + // sub_v2_v2v2(d_prev, co_prev, co_curr); /* precalc */ sub_v2_v2v2(d_next, co_curr, co_next); - /* normalize_v2(d_prev); */ /* precalc */ + // normalize_v2(d_prev); /* precalc */ normalize_v2(d_next); if ((do_test == false) || diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 6a2b56306d6..d6b189d484b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -289,7 +289,7 @@ void BKE_mball_texspace_calc(Object *ob) bb = ob->runtime.bb; /* Weird one, this. */ - /* INIT_MINMAX(min, max); */ + // INIT_MINMAX(min, max); (min)[0] = (min)[1] = (min)[2] = 1.0e30f; (max)[0] = (max)[1] = (max)[2] = -1.0e30f; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 18274d4023f..4aef0f346c3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -262,7 +262,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address CD_LAYERS_FREE(vlayers); CD_LAYERS_FREE(elayers); - /* CD_LAYER_FREE(flayers); */ /* Never allocated. */ + // CD_LAYER_FREE(flayers); /* Never allocated. */ CD_LAYERS_FREE(llayers); CD_LAYERS_FREE(players); @@ -942,7 +942,7 @@ Mesh *BKE_mesh_new_nomain( NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); BKE_libblock_init_empty(&mesh->id); - /* Don't use CustomData_reset(...); because we don't want to touch custom-data. */ + /* Don't use #CustomData_reset because we don't want to touch custom-data. */ copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index ca594470cba..4b1eb5b39ce 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -272,8 +272,8 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu, } if (totvert == 0) { - /* error("can't convert"); */ - /* Make Sure you check ob->data is a curve */ + /* Make Sure you check ob->data is a curve. */ + // error("can't convert"); return -1; } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 87b11904f90..6bd08b3dbe0 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -165,7 +165,7 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, pnors = (float(*)[3])MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__); } /* NO NEED TO ALLOC YET */ - /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ + // if (!fnors) {fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); } if (only_face_normals == false) { /* vertex normals are optional, they require some extra calculations, @@ -200,7 +200,7 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, if (pnors != r_polyNors) { MEM_freeN(pnors); } - /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */ + // if (fnors != r_faceNors) { MEM_freeN(fnors); } /* NO NEED TO ALLOC YET */ fnors = pnors = nullptr; } diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 4d003ddc900..e9683d3b52c 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -530,7 +530,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(t for (j = 0; j <= o->_N / 2; j++) { fftw_complex mul_param; - /* init_complex(mul_param, -scale, 0); */ + // init_complex(mul_param, -scale, 0); init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); @@ -563,7 +563,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(t for (j = 0; j <= o->_N / 2; j++) { fftw_complex mul_param; - /* init_complex(mul_param, -scale, 0); */ + // init_complex(mul_param, -scale, 0); init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); @@ -596,7 +596,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(t for (j = 0; j <= o->_N / 2; j++) { fftw_complex mul_param; - /* init_complex(mul_param, -scale, 0); */ + // init_complex(mul_param, -scale, 0); init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); @@ -1015,7 +1015,7 @@ bool BKE_ocean_init(struct Ocean *o, "ocean_fft_in_nz"); o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); - /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */ + // o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); /* (MEM01) */ o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); @@ -1083,7 +1083,7 @@ void BKE_ocean_free_data(struct Ocean *oc) fftw_destroy_plan(oc->_N_x_plan); fftw_destroy_plan(oc->_N_z_plan); MEM_freeN(oc->_N_x); - /* fftwf_free(oc->_N_y); (MEM01) */ + // fftwf_free(oc->_N_y); /* (MEM01) */ MEM_freeN(oc->_N_z); } diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c index 7ed70234baf..c5504b22b43 100644 --- a/source/blender/blenkernel/intern/ocean_spectrum.c +++ b/source/blender/blenkernel/intern/ocean_spectrum.c @@ -77,7 +77,7 @@ static float ocean_spectrum_wind_and_damp(const Ocean *oc, float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment); /* Eliminate wavelengths smaller than cutoff. */ - /* val *= exp(-k2 * m_cutoff); */ + // val *= exp(-k2 * m_cutoff); /* Reduce reflected waves. */ if (k_dot_w < 0.0f) { diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 5e92be76197..fbc781f5eb9 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2277,7 +2277,7 @@ static void softbody_calc_forces( float fieldfactor = -1.0f, windfactor = 0.25; int do_deflector /*, do_selfcollision */, do_springcollision, do_aero; - /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */ + // gravity = sb->grav * sb_grav_force_scale(ob); /* UNUSED */ /* check conditions for various options */ do_deflector = query_external_colliders(depsgraph, sb->collision_group); @@ -2749,7 +2749,7 @@ static void mesh_to_softbody(Object *ob) build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */ /* insert *other second order* springs if desired */ if (sb->secondspring > 0.0000001f) { - /* exploits the first run of build_bps_springlist(ob); */ + /* Exploits the first run of `build_bps_springlist(ob)`. */ add_2nd_order_springs(ob, sb->secondspring); /* yes we need to do it again. */ build_bps_springlist(ob); diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c index 62b4cee4af0..2ea7fbd9fbe 100644 --- a/source/blender/datatoc/datatoc.c +++ b/source/blender/datatoc/datatoc.c @@ -108,7 +108,7 @@ int main(int argc, char **argv) } #endif - /* fprintf (fpout, "\\x%02x", getc(fpin)); */ + // fprintf(fpout, "\\x%02x", getc(fpin)); fprintf(fpout, "%3d,", getc(fpin)); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index ba3d3b584d7..5cc52303cd6 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -341,7 +341,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) return (gpl->actframe->framenum == cfra); } /* XXX: disabled as could be too much of a penalty */ - /* return BKE_gpencil_layer_frame_find(gpl, cfra); */ + // return BKE_gpencil_layer_frame_find(gpl, cfra); } } diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index dbfdfbf7950..3149675ac04 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -343,7 +343,7 @@ static int ui_block_align_butal_cmp(const void *a, const void *b) * stupid UI code produces widgets which have the same TOP and LEFT positions... * We do not care really, * because this happens when UI is way too small to be usable anyway. */ - /* BLI_assert(0); */ + // BLI_assert(0); return 0; } diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 65104885d98..ebebf69bc11 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -2281,7 +2281,7 @@ static void ui_shadowbox(const rctf *rect, uint pos, uint color, float shadsize, immVertex2fv(pos, v3); /* corner shape */ - /* immAttr4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */ + // immAttr4ub(color, 0, 0, 0, alpha); /* Not needed, done above in previous tri. */ immVertex2fv(pos, v3); immAttr4ub(color, 0, 0, 0, 0); immVertex2fv(pos, v4); @@ -2293,7 +2293,7 @@ static void ui_shadowbox(const rctf *rect, uint pos, uint color, float shadsize, immVertex2fv(pos, v3); /* bottom quad */ - /* immAttr4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */ + // immAttr4ub(color, 0, 0, 0, alpha); /* Not needed, done above in previous tri. */ immVertex2fv(pos, v3); immAttr4ub(color, 0, 0, 0, 0); immVertex2fv(pos, v6); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index f64f95c5322..7a42c9d5d8b 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -1582,7 +1582,7 @@ static void vgroup_fix( mag = normalize_v3(norm); if (mag) { /* zeros fix */ d = -dot_v3v3(norm, coord); - /* dist = (dot_v3v3(norm, m.co) + d); */ /* UNUSED */ + // dist = (dot_v3v3(norm, m.co) + d); /* UNUSED */ moveCloserToDistanceFromPlane( depsgraph, scene_eval, object_eval, me, i, norm, coord, d, distToBe, strength, cp); } diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d1ef1b33023..08d741545a8 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2540,7 +2540,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN /* don't do for now because it selects entire text instead of * placing cursor at the end */ - /* UI_textbutton_activate_but(C, but); */ + // UI_textbutton_activate_but(C, but); } #if defined(WIN32) else if (!can_create_dir(params->dir)) { diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index ec5f443e2dc..f4c4b6cafcd 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -364,7 +364,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) } block = uiLayoutGetBlock(layout); - /* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */ + // UI_block_func_handle_set(block, do_graph_region_buttons, NULL); uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 5be6c69363e..738db28a2b6 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1773,7 +1773,7 @@ static void tree_element_to_path(TreeElement *te, char buf[128], *name; temnext = (TreeElement *)(ld->next->data); - /* tsenext = TREESTORE(temnext); */ /* UNUSED */ + // tsenext = TREESTORE(temnext); /* UNUSED */ nextptr = &temnext->rnaptr; name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL); diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 65a673940f8..362ee179e7d 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -968,9 +968,9 @@ void ElementResize(const TransInfo *t, float obsizemat[3][3]; /* Reorient the size mat to fit the oriented object. */ mul_m3_m3m3(obsizemat, tmat, td->axismtx); - /* print_m3("obsizemat", obsizemat); */ + // print_m3("obsizemat", obsizemat); TransMat3ToSize(obsizemat, td->axismtx, fsize); - /* print_v3("fsize", fsize); */ + // print_v3("fsize", fsize); } else { mat3_to_size(fsize, tmat); diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 066a2853dc7..cfcb17b8da0 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -852,7 +852,7 @@ static EdgeSlideData *createEdgeSlideVerts_double_side(TransInfo *t, TransDataCo #undef EDGESLIDE_VERT_IS_INNER } - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + // EDBM_flag_disable_all(em, BM_ELEM_SELECT); BLI_assert(STACK_SIZE(sv_array) == (uint)sv_tot); @@ -1037,7 +1037,7 @@ static EdgeSlideData *createEdgeSlideVerts_single_side(TransInfo *t, TransDataCo } } - /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + // EDBM_flag_disable_all(em, BM_ELEM_SELECT); sld->sv = sv_array; sld->totsv = sv_tot; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index a465c6b92bc..cd323e72003 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1711,7 +1711,7 @@ static const char *exr_rgba_channelname(MultiPartInputFile &file, const char *ch const ChannelList &channels = file.header(0).channels(); for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { - /* const Channel &channel = i.channel(); */ /* Not used yet */ + // const Channel &channel = i.channel(); /* Not used yet. */ const char *str = i.name(); int len = strlen(str); if (len) { diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index e52bdca0d87..e54192abc54 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -1363,7 +1363,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, calc_joint_parent_mat_rest(par, nullptr, root, node); mul_m4_m4m4(temp, par, matfra); - /* evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); */ + // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); /* calc special matrix */ mul_m4_series(mat, irest, temp, irest_dae, rest); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 7bc09e3cd67..ac734efed8b 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -3003,7 +3003,7 @@ void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value) BLI_assert(RNA_property_type(prop) == PROP_FLOAT); BLI_assert(RNA_property_array_check(prop) == false); /* useful to check on bad values but set function should clamp */ - /* BLI_assert(RNA_property_float_clamp(ptr, prop, &value) == 0); */ + // BLI_assert(RNA_property_float_clamp(ptr, prop, &value) == 0); if ((idprop = rna_idproperty_check(&prop, ptr))) { RNA_property_float_clamp(ptr, prop, &value); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 49d02524e43..690506fa517 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -56,7 +56,7 @@ static void rna_Armature_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), DEG_id_tag_update(id, 0); WM_main_add_notifier(NC_GEOM | ND_DATA, id); - /*WM_main_add_notifier(NC_OBJECT|ND_POSE, NULL); */ + // WM_main_add_notifier(NC_OBJECT|ND_POSE, NULL); } static void rna_Armature_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) @@ -994,7 +994,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) } RNA_def_property_float_sdna(prop, NULL, "rad_head"); /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */ - /*RNA_def_property_range(prop, 0, 1000); */ + // RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3); RNA_def_property_ui_text( prop, "Envelope Head Radius", "Radius of head of bone (for Envelope deform only)"); @@ -1008,7 +1008,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) } RNA_def_property_float_sdna(prop, NULL, "rad_tail"); /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */ - /*RNA_def_property_range(prop, 0, 1000); */ + // RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3); RNA_def_property_ui_text( prop, "Envelope Tail Radius", "Radius of tail of bone (for Envelope deform only)"); @@ -1346,7 +1346,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) /* calculated and read only, not actual data access */ prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); - /* RNA_def_property_float_sdna(prop, NULL, ""); */ /* Doesn't access any real data. */ + // RNA_def_property_float_sdna(prop, NULL, ""); /* Doesn't access any real data. */ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_THICK_WRAP); /* no reference to original data */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 9caff88a3a5..fbc578acb8e 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1687,7 +1687,7 @@ static void rna_def_mvert(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION); - /* RNA_def_property_float_sdna(prop, NULL, "no"); */ + // RNA_def_property_float_sdna(prop, NULL, "no"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_float_funcs( diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 5de7aa9a18b..b360d3b6672 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1036,7 +1036,7 @@ static void rna_NodeTree_get_from_context( void *ret1, *ret2, *ret3; RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */ - /* RNA_struct_find_function(&ptr, "get_from_context"); */ + // RNA_struct_find_function(&ptr, "get_from_context"); func = &rna_NodeTree_get_from_context_func; RNA_parameter_list_create(&list, &ptr, func); @@ -2987,7 +2987,7 @@ static void rna_NodeSocketInterface_register_properties(bNodeTree *ntree, } RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr); - /* RNA_struct_find_function(&ptr, "register_properties"); */ + // RNA_struct_find_function(&ptr, "register_properties"); func = &rna_NodeSocketInterface_register_properties_func; RNA_parameter_list_create(&list, &ptr, func); @@ -3013,7 +3013,7 @@ static void rna_NodeSocketInterface_init_socket( RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr); - /* RNA_struct_find_function(&ptr, "init_socket"); */ + // RNA_struct_find_function(&ptr, "init_socket"); func = &rna_NodeSocketInterface_init_socket_func; RNA_parameter_list_create(&list, &ptr, func); @@ -3043,7 +3043,7 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree, RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr); - /* RNA_struct_find_function(&ptr, "from_socket"); */ + // RNA_struct_find_function(&ptr, "from_socket"); func = &rna_NodeSocketInterface_from_socket_func; RNA_parameter_list_create(&list, &ptr, func); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index de4cfb2b61a..f732e14d905 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1851,20 +1851,20 @@ static void rna_def_particle(BlenderRNA *brna) prop = RNA_def_property(srna, "birth_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "time"); - /* RNA_def_property_range(prop, lowerLimitf, upperLimitf); */ + // RNA_def_property_range(prop, lowerLimitf, upperLimitf); RNA_def_property_ui_text(prop, "Birth Time", ""); prop = RNA_def_property(srna, "lifetime", PROP_FLOAT, PROP_TIME); - /* RNA_def_property_range(prop, lowerLimitf, upperLimitf); */ + // RNA_def_property_range(prop, lowerLimitf, upperLimitf); RNA_def_property_ui_text(prop, "Lifetime", ""); prop = RNA_def_property(srna, "die_time", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "dietime"); - /* RNA_def_property_range(prop, lowerLimitf, upperLimitf); */ + // RNA_def_property_range(prop, lowerLimitf, upperLimitf); RNA_def_property_ui_text(prop, "Die Time", ""); prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); - /* RNA_def_property_range(prop, lowerLimitf, upperLimitf); */ + // RNA_def_property_range(prop, lowerLimitf, upperLimitf); RNA_def_property_ui_text(prop, "Size", ""); /* */ @@ -3658,7 +3658,7 @@ static void rna_def_particle_system(BlenderRNA *brna) /* access to particle settings is redirected through functions */ /* to allow proper id-buttons functionality */ prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); - /*RNA_def_property_pointer_sdna(prop, NULL, "part"); */ + // RNA_def_property_pointer_sdna(prop, NULL, "part"); RNA_def_property_struct_type(prop, "ParticleSettings"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL); RNA_def_property_pointer_funcs( diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c index 43f0d27f514..2dce9d32006 100644 --- a/source/blender/makesrna/intern/rna_speaker.c +++ b/source/blender/makesrna/intern/rna_speaker.c @@ -55,7 +55,9 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Mute", "Mute the speaker"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND); - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "sound", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Sound"); @@ -63,24 +65,30 @@ static void rna_def_speaker(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Sound", "Sound data-block used by this speaker"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_sound_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_sound_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "volume_max", PROP_FLOAT, PROP_FACTOR); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Maximum Volume", "Maximum volume, no matter how near the object is"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_max_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_max_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "volume_min", PROP_FLOAT, PROP_FACTOR); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Minimum Volume", "Minimum volume, no matter how far away the object is"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_min_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_min_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -89,24 +97,30 @@ static void rna_def_speaker(BlenderRNA *brna) prop, "Maximum Distance", "Maximum distance for volume calculation, no matter how far away the object is"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_max_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_max_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "distance_reference", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_text( prop, "Reference Distance", "Reference distance at which volume is 100%"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_reference_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_reference_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "attenuation", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_text( prop, "Attenuation", "How strong the distance affects volume, depending on distance model"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_attenuation_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_attenuation_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "cone_angle_outer", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -116,8 +130,10 @@ static void rna_def_speaker(BlenderRNA *brna) "Outer Cone Angle", "Angle of the outer cone, in degrees, outside this cone the volume is " "the outer cone volume, between inner and outer cone the volume is interpolated"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_outer_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_outer_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "cone_angle_inner", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -126,29 +142,37 @@ static void rna_def_speaker(BlenderRNA *brna) prop, "Inner Cone Angle", "Angle of the inner cone, in degrees, inside the cone the volume is 100%"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_inner_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_inner_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "cone_volume_outer", PROP_FLOAT, PROP_FACTOR); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Outer Cone Volume", "Volume outside the outer cone"); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_volume_outer_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_volume_outer_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "How loud the sound is"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif prop = RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.1f, 10.0f); RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND); - /* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_pitch_set", NULL); */ - /* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */ +# if 0 + RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_pitch_set", NULL); + RNA_def_property_update(prop, 0, "rna_Speaker_update"); +# endif /* common */ rna_def_animdata_common(srna); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index a88b100435a..c506a533032 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1458,7 +1458,7 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->description"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Panel_bl_description_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ @@ -1820,7 +1820,7 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->description"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Menu_bl_description_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 667f3822935..b910648495b 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1915,7 +1915,7 @@ static void rna_def_operator(BlenderRNA *brna) /* Without setting the length the pointer size would be used. -3 because `.` -> `_OT_`. */ RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME - 3); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_idname_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_struct_name_property(srna, prop); @@ -1923,7 +1923,7 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->name"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_label_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE); @@ -1943,7 +1943,7 @@ static void rna_def_operator(BlenderRNA *brna) "rna_Operator_bl_description_get", "rna_Operator_bl_description_length", "rna_Operator_bl_description_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); @@ -1953,7 +1953,7 @@ static void rna_def_operator(BlenderRNA *brna) "rna_Operator_bl_undo_group_get", "rna_Operator_bl_undo_group_length", "rna_Operator_bl_undo_group_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); @@ -2013,7 +2013,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->idname"); RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_idname_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_struct_name_property(srna, prop); @@ -2021,7 +2021,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->name"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_label_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE); @@ -2041,7 +2041,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) "rna_Operator_bl_description_get", "rna_Operator_bl_description_length", "rna_Operator_bl_description_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); @@ -2051,7 +2051,7 @@ static void rna_def_macro_operator(BlenderRNA *brna) "rna_Operator_bl_undo_group_get", "rna_Operator_bl_undo_group_length", "rna_Operator_bl_undo_group_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); @@ -2073,11 +2073,13 @@ static void rna_def_operator_type_macro(BlenderRNA *brna) srna, "Operator Macro", "Storage of a sub operator in a macro after it has been added"); RNA_def_struct_sdna(srna, "wmOperatorTypeMacro"); - /* prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); */ - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ - /* RNA_def_property_string_sdna(prop, NULL, "idname"); */ - /* RNA_def_property_ui_text(prop, "Name", "Name of the sub operator"); */ - /* RNA_def_struct_name_property(srna, prop); */ +# if 0 + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_sdna(prop, NULL, "idname"); + RNA_def_property_ui_text(prop, "Name", "Name of the sub operator"); + RNA_def_struct_name_property(srna, prop); +# endif prop = RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index bde15daa682..e123604cbe9 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -230,7 +230,7 @@ static wmKeyMapItem *rna_KeyMap_item_new(wmKeyMap *km, bool repeat, bool head) { - /* wmWindowManager *wm = CTX_wm_manager(C); */ + // wmWindowManager *wm = CTX_wm_manager(C); wmKeyMapItem *kmi = NULL; char idname_bl[OP_MAX_TYPENAME]; int modifier = 0; diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 6a1574f3dbe..febb0e14e07 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -80,7 +80,7 @@ static void rna_gizmo_draw_cb(const struct bContext *C, struct wmGizmo *gz) ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "draw"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "draw")` directly. */ func = &rna_Gizmo_draw_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -98,7 +98,7 @@ static void rna_gizmo_draw_select_cb(const struct bContext *C, struct wmGizmo *g ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "draw_select"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "draw_select")` directly. */ func = &rna_Gizmo_draw_select_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -117,7 +117,7 @@ static int rna_gizmo_test_select_cb(struct bContext *C, struct wmGizmo *gz, cons ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "test_select"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "test_select")` directly. */ func = &rna_Gizmo_test_select_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -144,7 +144,7 @@ static int rna_gizmo_modal_cb(struct bContext *C, FunctionRNA *func; const int tweak_flag_int = tweak_flag; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "modal"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "modal")` directly. */ func = &rna_Gizmo_modal_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -168,7 +168,7 @@ static void rna_gizmo_setup_cb(struct wmGizmo *gz) ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "setup"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "setup")` directly. */ func = &rna_Gizmo_setup_func; RNA_parameter_list_create(&list, &gz_ptr, func); gzgroup->type->rna_ext.call((bContext *)NULL, &gz_ptr, func, &list); @@ -183,7 +183,7 @@ static int rna_gizmo_invoke_cb(struct bContext *C, struct wmGizmo *gz, const str ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "invoke"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "invoke")` directly. */ func = &rna_Gizmo_invoke_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -206,7 +206,7 @@ static void rna_gizmo_exit_cb(struct bContext *C, struct wmGizmo *gz, bool cance ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "exit"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "exit")` directly. */ func = &rna_Gizmo_exit_func; RNA_parameter_list_create(&list, &gz_ptr, func); RNA_parameter_set_lookup(&list, "context", &C); @@ -226,7 +226,7 @@ static void rna_gizmo_select_refresh_cb(struct wmGizmo *gz) ParameterList list; FunctionRNA *func; RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr); - /* RNA_struct_find_function(&gz_ptr, "select_refresh"); */ + /* Reference `RNA_struct_find_function(&gz_ptr, "select_refresh")` directly. */ func = &rna_Gizmo_select_refresh_func; RNA_parameter_list_create(&list, &gz_ptr, func); gzgroup->type->rna_ext.call((bContext *)NULL, &gz_ptr, func, &list); @@ -785,7 +785,7 @@ static void rna_gizmogroup_invoke_prepare_cb(const bContext *C, FunctionRNA *func; RNA_pointer_create(NULL, gzgroup->type->rna_ext.srna, gzgroup, &gzgroup_ptr); - /* RNA_struct_find_function(&wgroupr, "invoke_prepare"); */ + /* Reference `RNA_struct_find_function(&wgroupr, "invoke_prepare")` directly. */ func = &rna_GizmoGroup_invoke_prepare_func; RNA_parameter_list_create(&list, &gzgroup_ptr, func); @@ -1033,7 +1033,7 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_string_sdna(prop, NULL, "type->idname"); RNA_def_property_string_maxlength(prop, MAX_NAME); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Gizmo_bl_idname_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); RNA_define_verify_sdna(1); /* not in sdna */ @@ -1362,7 +1362,7 @@ static void rna_def_gizmogroup(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->name"); RNA_def_property_string_maxlength(prop, MAX_NAME); /* else it uses the pointer size! */ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GizmoGroup_bl_label_set"); - /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 1ca0eb74cf5..a66e3090548 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -216,7 +216,7 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_world_color); RNA_def_property_ui_text(prop, "Color", "Color of the background"); - /* RNA_def_property_update(prop, 0, "rna_World_update"); */ + // RNA_def_property_update(prop, 0, "rna_World_update"); /* render-only uses this */ RNA_def_property_update(prop, 0, "rna_World_draw_update"); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 17cbf8e4569..6dd96f66cec 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7505,7 +7505,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna) /* Newclass will now have 2 ref's, ???, * probably 1 is internal since #Py_DECREF here segfaults. */ - /* PyC_ObSpit("new class ref", newclass); */ + // PyC_ObSpit("new class ref", newclass); if (newclass) { /* srna owns one, and the other is owned by the caller. */ diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index abbc332d89d..fcc796d4545 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -334,7 +334,7 @@ static int validate_array_length(PyObject *rvalue, } if (tot != len) { - /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */ + // BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d", error_prefix, diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index fec5a516688..7c3fce7fcb2 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -485,11 +485,11 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) } /* XXX We'd need re-entrant locking on Main for this to work... */ - /* BKE_main_lock(bmain); */ + // BKE_main_lock(bmain); wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); - /* BKE_main_unlock(bmain); */ + // BKE_main_unlock(bmain); /* mark all library linked objects to be updated */ BKE_main_lib_objects_recalc_all(bmain); -- cgit v1.2.3 From c741558509a35317209bbfd3ff77c413f791a47c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 14:34:43 +1000 Subject: Cleanup: spelling in comments --- source/blender/compositor/operations/COM_DilateErodeOperation.cc | 2 +- source/blender/draw/engines/select/select_debug_engine.c | 2 +- source/blender/editors/space_file/file_ops.c | 4 ++-- source/blender/makesdna/DNA_ID.h | 2 +- source/blender/makesdna/intern/makesdna.c | 4 ++-- source/blender/python/mathutils/mathutils_geometry.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc index c67a35b686c..a27148f967d 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc @@ -500,7 +500,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; - /* NOTE: Cache buffer has original tilesize width, but new height. + /* NOTE: Cache buffer has original tile-size width, but new height. * We have to calculate the additional rows in the first pass, * to have valid data available for the second pass. */ tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax); diff --git a/source/blender/draw/engines/select/select_debug_engine.c b/source/blender/draw/engines/select/select_debug_engine.c index ded96be23f3..e9437c5ab92 100644 --- a/source/blender/draw/engines/select/select_debug_engine.c +++ b/source/blender/draw/engines/select/select_debug_engine.c @@ -19,7 +19,7 @@ /** \file * \ingroup draw_engine * - * Engine for debuging the selection map drawing. + * Engine for debugging the selection map drawing. */ #include "DNA_ID.h" diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 08d741545a8..2f1acd2ca4d 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1388,8 +1388,8 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my) FileSelectParams *params; int numfiles, origfile; - /* In case blender starts where the mouse is over a File broser, this operator can be invoked - * when the sfile or sfile->layout isn't initialized yet. */ + /* In case blender starts where the mouse is over a File browser, + * this operator can be invoked when the `sfile` or `sfile->layout` isn't initialized yet. */ if (sfile == NULL || sfile->files == NULL || sfile->layout == NULL) { return 0; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 8a577be2749..10a5a0f1c47 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -587,7 +587,7 @@ enum { * * RESET_NEVER * - * NOTE: Only used by nodegroups currently. + * NOTE: Only used by node-groups currently. */ LIB_TAG_LOCALIZED = 1 << 14, diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 8324db1a9c8..061c3462a69 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1118,11 +1118,11 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char types_align_32[structtype] = max_align_32; types_align_64[structtype] = max_align_64; - /* Santiy check 1: alignment should never be 0. */ + /* Sanity check 1: alignment should never be 0. */ BLI_assert(max_align_32); BLI_assert(max_align_64); - /* Santiy check 2: alignment should always be equal or smaller than the maximum + /* Sanity check 2: alignment should always be equal or smaller than the maximum * size of a build in type which is 8 bytes (ie int64_t or double). */ BLI_assert(max_align_32 <= 8); BLI_assert(max_align_64 <= 8); diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 3c0ea9a9566..5868c76b28f 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -201,7 +201,7 @@ static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject } if (result == 0) { - /* Co-linear. */ + /* Collinear. */ Py_RETURN_NONE; } -- cgit v1.2.3 From 216414c65a6b3690aba75caf74d1dbf6dd8247a1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 14:24:27 +1000 Subject: Cleanup: use parameters struct for wm_homefile_read Also add wm_homefile_read_ex which is only needed for the first execution at startup. --- source/blender/windowmanager/intern/wm_files.c | 80 +++++++++++----------- source/blender/windowmanager/intern/wm_init_exit.c | 23 +++---- source/blender/windowmanager/wm_files.h | 43 +++++++++--- 3 files changed, 85 insertions(+), 61 deletions(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index abf957a6396..65659dd7ab7 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -993,31 +993,12 @@ const char *WM_init_state_app_template_get(void) /** * Called on startup, (context entirely filled with NULLs) - * or called for 'New File' both startup.blend and userpref.blend are checked. - * - * \param use_factory_settings: - * Ignore on-disk startup file, use bundled `datatoc_startup_blend` instead. - * Used for "Restore Factory Settings". - * - * \param use_userdef: Load factory settings as well as startup file. - * Disabled for "File New" we don't want to reload preferences. - * - * \param filepath_startup_override: - * Optional path pointing to an alternative blend file (may be NULL). - * - * \param app_template_override: - * Template to use instead of the template defined in user-preferences. - * When not-null, this is written into the user preferences. + * or called for 'New File' both `startup.blend` and `userpref.blend` are checked. */ -void wm_homefile_read(bContext *C, - ReportList *reports, - bool use_factory_settings, - bool use_empty_data, - bool use_data, - bool use_userdef, - const char *filepath_startup_override, - const char *app_template_override, - bool *r_is_factory_startup) +void wm_homefile_read_ex(bContext *C, + const struct wmHomeFileRead_Params *params_homefile, + ReportList *reports, + bool *r_is_factory_startup) { #if 0 /* UNUSED, keep as this may be needed later & the comment below isn't self evident. */ /* Context does not always have valid main pointer here. */ @@ -1026,6 +1007,14 @@ void wm_homefile_read(bContext *C, ListBase wmbase; bool success = false; + /* May be enabled, when the user configuration doesn't exist. */ + const bool use_data = params_homefile->use_data; + const bool use_userdef = params_homefile->use_userdef; + bool use_factory_settings = params_homefile->use_factory_settings; + const bool use_empty_data = params_homefile->use_empty_data; + const char *filepath_startup_override = params_homefile->filepath_startup_override; + const char *app_template_override = params_homefile->app_template_override; + bool filepath_startup_is_factory = true; char filepath_startup[FILE_MAX]; char filepath_userdef[FILE_MAX]; @@ -1320,6 +1309,13 @@ void wm_homefile_read(bContext *C, } } +void wm_homefile_read(bContext *C, + const struct wmHomeFileRead_Params *params_homefile, + ReportList *reports) +{ + wm_homefile_read_ex(C, params_homefile, reports, NULL); +} + /* -------------------------------------------------------------------- */ /** \name Blend-File History API * \{ */ @@ -2087,14 +2083,15 @@ static int wm_userpref_read_exec(bContext *C, wmOperator *op) UserDef U_backup = U; wm_homefile_read(C, - op->reports, - use_factory_settings, - false, - use_data, - use_userdef, - NULL, - WM_init_state_app_template_get(), - NULL); + &(const struct wmHomeFileRead_Params){ + .use_data = use_data, + .use_userdef = use_userdef, + .use_factory_settings = use_factory_settings, + .use_empty_data = false, + .filepath_startup_override = NULL, + .app_template_override = WM_init_state_app_template_get(), + }, + op->reports); wm_userpref_read_exceptions(&U, &U_backup); SET_FLAG_FROM_TEST(G.f, use_factory_settings, G_FLAG_USERPREF_NO_SAVE_ON_EXIT); @@ -2233,16 +2230,17 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) app_template = WM_init_state_app_template_get(); } - bool use_data = true; wm_homefile_read(C, - op->reports, - use_factory_settings, - use_empty_data, - use_data, - use_userdef, - filepath, - app_template, - NULL); + &(const struct wmHomeFileRead_Params){ + .use_data = true, + .use_userdef = use_userdef, + .use_factory_settings = use_factory_settings, + .use_empty_data = use_empty_data, + .filepath_startup_override = filepath, + .app_template_override = app_template, + }, + op->reports); + if (use_splash) { WM_init_splash(C); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index d7ea47fc625..953aa683441 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -279,10 +279,7 @@ void WM_init(bContext *C, int argc, const char **argv) WM_msgbus_types_init(); - /* get the default database, plus a wm */ bool is_factory_startup = true; - const bool use_data = true; - const bool use_userdef = true; /* Studio-lights needs to be init before we read the home-file, * otherwise the versioning cannot find the default studio-light. */ @@ -290,15 +287,17 @@ void WM_init(bContext *C, int argc, const char **argv) BLI_assert((G.fileflags & G_FILE_NO_UI) == 0); - wm_homefile_read(C, - NULL, - G.factory_startup, - false, - use_data, - use_userdef, - NULL, - WM_init_state_app_template_get(), - &is_factory_startup); + wm_homefile_read_ex(C, + &(const struct wmHomeFileRead_Params){ + .use_data = true, + .use_userdef = true, + .use_factory_settings = G.factory_startup, + .use_empty_data = false, + .filepath_startup_override = NULL, + .app_template_override = WM_init_state_app_template_get(), + }, + NULL, + &is_factory_startup); /* Call again to set from userpreferences... */ BLT_lang_set(NULL); diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index c7fe07cad7f..7009885495b 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -33,15 +33,42 @@ extern "C" { /* wm_files.c */ void wm_history_file_read(void); + +struct wmHomeFileRead_Params { + /** Load data, disable when only loading user preferences. */ + unsigned int use_data : 1; + /** Load factory settings as well as startup file (disabled for "File New"). */ + unsigned int use_userdef : 1; + + /** + * Ignore on-disk startup file, use bundled `datatoc_startup_blend` instead. + * Used for "Restore Factory Settings". + */ + unsigned int use_factory_settings : 1; + /** + * Load the startup file without any data-blocks. + * Useful for automated content generation, so the file starts without data. + */ + unsigned int use_empty_data : 1; + /** + * Optional path pointing to an alternative blend file (may be NULL). + */ + const char *filepath_startup_override; + /** + * Template to use instead of the template defined in user-preferences. + * When not-null, this is written into the user preferences. + */ + const char *app_template_override; +}; + +void wm_homefile_read_ex(struct bContext *C, + const struct wmHomeFileRead_Params *params_homefile, + struct ReportList *reports, + bool *r_is_factory_startup); void wm_homefile_read(struct bContext *C, - struct ReportList *reports, - bool use_factory_settings, - bool use_empty_data, - bool use_data, - bool use_userdef, - const char *filepath_startup_override, - const char *app_template_override, - bool *r_is_factory_startup); + const struct wmHomeFileRead_Params *params_homefile, + struct ReportList *reports); + void wm_file_read_report(bContext *C, struct Main *bmain); void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); -- cgit v1.2.3 From 497bc4d19977abc7b9e2c0f5024a23057e680954 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 14:50:40 +1000 Subject: Fix T89046: Startup file with Python drivers crashes on load Resolve order of initialization error reading startup file, support postponing running wm_file_read_post until Blender has been initialized. Deferring updates allows duplicate initialization to be removed from WM_init. Reviewed By: mont29 Ref D12184 --- source/blender/windowmanager/intern/wm_files.c | 75 ++++++++++++++++++---- source/blender/windowmanager/intern/wm_init_exit.c | 56 ++++++---------- source/blender/windowmanager/wm_files.h | 6 +- 3 files changed, 88 insertions(+), 49 deletions(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 65659dd7ab7..21c16e94097 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -595,20 +595,34 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef UI_view2d_zoom_cache_reset(); } +/** + * Parameters for #wm_file_read_post, also used for deferred initialization. + */ +struct wmFileReadPost_Params { + uint use_data : 1; + uint use_userdef : 1; + + uint is_startup_file : 1; + uint is_factory_startup : 1; + uint reset_app_template : 1; +}; + /** * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ -static void wm_file_read_post(bContext *C, - const bool is_startup_file, - const bool is_factory_startup, - const bool use_data, - const bool use_userdef, - const bool reset_app_template) +static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *params) { - bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); + const bool use_data = params->use_data; + const bool use_userdef = params->use_userdef; + const bool is_startup_file = params->is_startup_file; + const bool is_factory_startup = params->is_factory_startup; + const bool reset_app_template = params->reset_app_template; + + bool addons_loaded = false; + if (use_data) { if (!G.background) { /* remove windows which failed to be added via WM_check */ @@ -910,7 +924,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) wm_history_file_update(); } - wm_file_read_post(C, false, false, use_data, use_userdef, false); + wm_file_read_post(C, + &(const struct wmFileReadPost_Params){ + .use_data = use_data, + .use_userdef = use_userdef, + .is_startup_file = false, + .is_factory_startup = false, + .reset_app_template = false, + }); bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole; file_read_reports_finalize(&bf_reports); @@ -994,11 +1015,17 @@ const char *WM_init_state_app_template_get(void) /** * Called on startup, (context entirely filled with NULLs) * or called for 'New File' both `startup.blend` and `userpref.blend` are checked. + * + * \param r_params_file_read_post: Support postponed initialization, + * needed for initial startup when only some sub-systems have been initialized. + * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored + * in this return argument. + * The caller is responsible for calling #wm_homefile_read_post with this return argument. */ void wm_homefile_read_ex(bContext *C, const struct wmHomeFileRead_Params *params_homefile, ReportList *reports, - bool *r_is_factory_startup) + struct wmFileReadPost_Params **r_params_file_read_post) { #if 0 /* UNUSED, keep as this may be needed later & the comment below isn't self evident. */ /* Context does not always have valid main pointer here. */ @@ -1302,10 +1329,21 @@ void wm_homefile_read_ex(bContext *C, G.save_over = 0; } - wm_file_read_post(C, true, is_factory_startup, use_data, use_userdef, reset_app_template); - - if (r_is_factory_startup) { - *r_is_factory_startup = is_factory_startup; + { + const struct wmFileReadPost_Params params_file_read_post = { + .use_data = use_data, + .use_userdef = use_userdef, + .is_startup_file = true, + .is_factory_startup = is_factory_startup, + .reset_app_template = reset_app_template, + }; + if (r_params_file_read_post == NULL) { + wm_file_read_post(C, ¶ms_file_read_post); + } + else { + *r_params_file_read_post = MEM_mallocN(sizeof(struct wmFileReadPost_Params), __func__); + **r_params_file_read_post = params_file_read_post; + } } } @@ -1316,6 +1354,17 @@ void wm_homefile_read(bContext *C, wm_homefile_read_ex(C, params_homefile, reports, NULL); } +/** + * Special case, support deferred execution of #wm_file_read_post, + * Needed when loading for the first time to workaround order of initialization bug, see T89046. + */ +void wm_homefile_read_post(struct bContext *C, + const struct wmFileReadPost_Params *params_file_read_post) +{ + wm_file_read_post(C, params_file_read_post); + MEM_freeN((void *)params_file_read_post); +} + /* -------------------------------------------------------------------- */ /** \name Blend-File History API * \{ */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 953aa683441..4b839384853 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -279,14 +279,31 @@ void WM_init(bContext *C, int argc, const char **argv) WM_msgbus_types_init(); - bool is_factory_startup = true; - /* Studio-lights needs to be init before we read the home-file, * otherwise the versioning cannot find the default studio-light. */ BKE_studiolight_init(); BLI_assert((G.fileflags & G_FILE_NO_UI) == 0); + /** + * NOTE(@campbellbarton): Startup file and order of initialization. + * + * Loading #BLENDER_STARTUP_FILE, #BLENDER_USERPREF_FILE, starting Python and other sub-systems, + * have inter-dependencies, for example. + * + * - Some sub-systems depend on the preferences (initializing icons depend on the theme). + * - Add-ons depends on the preferences to know what has been enabled. + * - Add-ons depends on the window-manger to register their key-maps. + * - Evaluating the startup file depends on Python for animation-drivers (see T89046). + * - Starting Python depends on the startup file so key-maps can be added in the window-manger. + * + * Loading preferences early, then application subsystems and finally the startup data would + * simplify things if it weren't for key-maps being part of the window-manager + * which is blend file data. + * Creating a dummy window-manager early, or moving the key-maps into the preferences + * would resolve this and may be worth looking into long-term, see: D12184 for details. + */ + struct wmFileReadPost_Params *params_file_read_post = NULL; wm_homefile_read_ex(C, &(const struct wmHomeFileRead_Params){ .use_data = true, @@ -297,7 +314,7 @@ void WM_init(bContext *C, int argc, const char **argv) .app_template_override = WM_init_state_app_template_get(), }, NULL, - &is_factory_startup); + ¶ms_file_read_post); /* Call again to set from userpreferences... */ BLT_lang_set(NULL); @@ -327,14 +344,6 @@ void WM_init(bContext *C, int argc, const char **argv) ED_spacemacros_init(); - /* NOTE(campbell): there is a bug where python needs initializing before loading the - * startup.blend because it may contain PyDrivers. It also needs to be after - * initializing space types and other internal data. - * - * However can't redo this at the moment. Solution is to load python - * before wm_homefile_read() or make py-drivers check if python is running. - * Will try fix when the crash can be repeated. */ - #ifdef WITH_PYTHON BPY_python_start(C, argc, argv); BPY_python_reset(C); @@ -374,30 +383,7 @@ void WM_init(bContext *C, int argc, const char **argv) } #endif - { - Main *bmain = CTX_data_main(C); - /* NOTE: logic here is from wm_file_read_post, - * call functions that depend on Python being initialized. */ - - /* normally 'wm_homefile_read' will do this, - * however python is not initialized when called from this function. - * - * unlikely any handlers are set but its possible, - * note that recovering the last session does its own callbacks. */ - CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); - - BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE); - BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST); - if (is_factory_startup) { - BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST); - } - - wm_file_read_report(C, bmain); - - if (!G.background) { - CTX_wm_window_set(C, NULL); - } - } + wm_homefile_read_post(C, params_file_read_post); } void WM_init_splash(bContext *C) diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 7009885495b..2fa5a68829e 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -24,6 +24,7 @@ #pragma once struct Main; +struct wmFileReadPost_Params; struct wmGenericCallback; struct wmOperatorType; @@ -64,11 +65,14 @@ struct wmHomeFileRead_Params { void wm_homefile_read_ex(struct bContext *C, const struct wmHomeFileRead_Params *params_homefile, struct ReportList *reports, - bool *r_is_factory_startup); + struct wmFileReadPost_Params **r_params_file_read_post); void wm_homefile_read(struct bContext *C, const struct wmHomeFileRead_Params *params_homefile, struct ReportList *reports); +void wm_homefile_read_post(struct bContext *C, + const struct wmFileReadPost_Params *params_file_read_post); + void wm_file_read_report(bContext *C, struct Main *bmain); void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); -- cgit v1.2.3 From 83603ba26a506a9b666bb7b0b1b6856ac69e834c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 16:10:10 +1000 Subject: Cleanup: comments/disabled code - Remove old comment for editors with weak syntax highlighting. - Remove disabled code to initialize Blender with a file path. - Remove file name references to function names since these were outdated, modern development environments can look up this info. --- source/blender/makesrna/intern/rna_access.c | 3 +- source/blender/windowmanager/intern/wm_init_exit.c | 45 ++++++++++------------ 2 files changed, 22 insertions(+), 26 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index ac734efed8b..a795d78a058 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -883,8 +883,7 @@ bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna) PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier) { - if (identifier[0] == '[' && identifier[1] == '"') { /* " (dummy comment to avoid confusing some - * function lists in text editors) */ + if (identifier[0] == '[' && identifier[1] == '"') { /* id prop lookup, not so common */ PropertyRNA *r_prop = NULL; PointerRNA r_ptr; /* only support single level props */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 4b839384853..a8d2e000108 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -222,7 +222,10 @@ static void sound_jack_sync_callback(Main *bmain, int mode, double time) } } -/* only called once, for startup */ +/** + * Initialize Blender and load the startup file & preferences + * (only called once). + */ void WM_init(bContext *C, int argc, const char **argv) { @@ -248,24 +251,22 @@ void WM_init(bContext *C, int argc, const char **argv) ED_undosys_type_init(); - BKE_library_callback_free_notifier_reference_set( - WM_main_remove_notifier_reference); /* lib_id.c */ - BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove); /* screen.c */ + BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); + BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove); BKE_region_callback_refresh_tag_gizmomap_set(WM_gizmomap_tag_refresh); - BKE_library_callback_remap_editor_id_reference_set( - WM_main_remap_editor_id_reference); /* lib_id.c */ - BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ + BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); + BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); DEG_editors_set_update_cb(ED_render_id_flush_update, ED_render_scene_update); - ED_spacetypes_init(); /* editors/space_api/spacetype.c */ + ED_spacetypes_init(); ED_node_init_butfuncs(); BLF_init(); BLT_lang_init(); - /* Must call first before doing any '.blend' file reading, - * since versioning code may create new IDs... See T57066. */ + /* Must call first before doing any `.blend` file reading, + * since versioning code may create new IDs. See T57066. */ BLT_lang_set(NULL); /* Init icons before reading .blend files for preview icons, which can @@ -273,7 +274,7 @@ void WM_init(bContext *C, int argc, const char **argv) * for scripts that do background processing with preview icons. */ BKE_icons_init(BIFICONID_LAST); - /* reports can't be initialized before the wm, + /* Reports can't be initialized before the window-manager, * but keep before file reading, since that may report errors */ wm_init_reports(C); @@ -316,10 +317,14 @@ void WM_init(bContext *C, int argc, const char **argv) NULL, ¶ms_file_read_post); - /* Call again to set from userpreferences... */ + /* NOTE: leave `G_MAIN->name` set to an empty string since this + * matches behavior after loading a new file. */ + BLI_assert(G_MAIN->name[0] == '\0'); + + /* Call again to set from preferences. */ BLT_lang_set(NULL); - /* For fsMenu. Called here so can include user preference paths if needed. */ + /* For file-system. Called here so can include user preference paths if needed. */ ED_file_init(); /* That one is generated on demand, we need to be sure it's clear on init. */ @@ -328,12 +333,13 @@ void WM_init(bContext *C, int argc, const char **argv) if (!G.background) { #ifdef WITH_INPUT_NDOF - /* sets 3D mouse deadzone */ + /* Sets 3D mouse dead-zone. */ WM_ndof_deadzone_set(U.ndof_deadzone); #endif WM_init_opengl(); if (!WM_platform_support_perform_checks()) { + /* No attempt to avoid memory leaks here. */ exit(-1); } @@ -348,8 +354,7 @@ void WM_init(bContext *C, int argc, const char **argv) BPY_python_start(C, argc, argv); BPY_python_reset(C); #else - (void)argc; /* unused */ - (void)argv; /* unused */ + UNUSED_VARS(argc, argv); #endif if (!G.background) { @@ -366,14 +371,6 @@ void WM_init(bContext *C, int argc, const char **argv) wm_history_file_read(); - /* allow a path of "", this is what happens when making a new file */ -#if 0 - if (BKE_main_blendfile_path_from_global()[0] == '\0') { - BLI_join_dirfile( - G_MAIN->name, sizeof(G_MAIN->name), BKE_appdir_folder_default(), "untitled.blend"); - } -#endif - BLI_strncpy(G.lib, BKE_main_blendfile_path_from_global(), sizeof(G.lib)); #ifdef WITH_COMPOSITOR -- cgit v1.2.3 From 806bf3f4527cf35b4510a3934bc73604d3f2b253 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 16:22:10 +1000 Subject: datadoc: add newlines to generated source files --- source/blender/datatoc/datatoc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c index 2ea7fbd9fbe..816353be9de 100644 --- a/source/blender/datatoc/datatoc.c +++ b/source/blender/datatoc/datatoc.c @@ -100,13 +100,12 @@ int main(int argc, char **argv) fprintf(fpout, "const int datatoc_%s_size = %d;\n", argv[1], (int)size); fprintf(fpout, "const char datatoc_%s[] = {\n", argv[1]); while (size--) { - /* if we want to open in an editor - * this is nicer to avoid very long lines */ -#ifdef VERBOSE + /* Even though this file is generated and doesn't need new-lines, + * these files may be loaded by developers when looking up symbols. + * Avoid a very long single line that may lock-up some editors. */ if (size % 32 == 31) { fprintf(fpout, "\n"); } -#endif // fprintf(fpout, "\\x%02x", getc(fpin)); fprintf(fpout, "%3d,", getc(fpin)); -- cgit v1.2.3 From 04ef718226e800c376e370c2d219444b44817a29 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 16:44:39 +1000 Subject: RNA: include base types in RNA_struct_type_find_property search Add RNA_struct_type_find_property_no_base for use in the rare situations when this isn't desired. Resolves T90617, where sequence strip sub-types weren't detecting properties that exist in the base "Sequence" types. --- source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_access.c | 17 ++++++++++++++++- source/blender/python/intern/bpy_rna.c | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 1eeb68c3a23..f206bde4705 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -828,6 +828,7 @@ unsigned int RNA_struct_count_properties(StructRNA *srna); /* lower level functions for access to type properties */ const struct ListBase *RNA_struct_type_properties(StructRNA *srna); +PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier); PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier); FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index a795d78a058..216e58a9c52 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -967,11 +967,26 @@ const struct ListBase *RNA_struct_type_properties(StructRNA *srna) return &srna->cont.properties; } -PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier) +PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier) { return BLI_findstring_ptr(&srna->cont.properties, identifier, offsetof(PropertyRNA, identifier)); } +/** + * \note #RNA_struct_find_property is a higher level alternative to this function + * which takes a #PointerRNA instead of a #StructRNA. + */ +PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier) +{ + for (; srna; srna = srna->base) { + PropertyRNA *prop = RNA_struct_type_find_property_no_base(srna, identifier); + if (prop != NULL) { + return prop; + } + } + return NULL; +} + FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier) { #if 1 diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 6dd96f66cec..ac1a7f68885 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4475,7 +4475,7 @@ static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *attr if ((ret == NULL) /* || BPy_PropDeferred_CheckTypeExact(ret) */ ) { StructRNA *srna = srna_from_self(cls, "StructRNA.__getattr__"); if (srna) { - PropertyRNA *prop = RNA_struct_type_find_property(srna, PyUnicode_AsUTF8(attr)); + PropertyRNA *prop = RNA_struct_type_find_property_no_base(srna, PyUnicode_AsUTF8(attr)); if (prop) { PointerRNA tptr; PyErr_Clear(); /* Clear error from tp_getattro. */ @@ -4497,7 +4497,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb const char *attr_str = PyUnicode_AsUTF8(attr); if (srna && !pyrna_write_check() && - (is_deferred_prop || RNA_struct_type_find_property(srna, attr_str))) { + (is_deferred_prop || RNA_struct_type_find_property_no_base(srna, attr_str))) { PyErr_Format(PyExc_AttributeError, "pyrna_struct_meta_idprop_setattro() " "can't set in readonly state '%.200s.%S'", -- cgit v1.2.3 From ad2fb92e9c8ff302d3bddbe77d7504bd8d307aca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 17:42:04 +1000 Subject: Cleanup: remove redundant variable --- source/blender/makesrna/intern/rna_access.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 216e58a9c52..41c31dfebcb 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -991,10 +991,9 @@ FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier) { #if 1 FunctionRNA *func; - StructRNA *type; - for (type = srna; type; type = type->base) { + for (; srna; srna = srna->base) { func = (FunctionRNA *)BLI_findstring_ptr( - &type->functions, identifier, offsetof(FunctionRNA, identifier)); + &srna->functions, identifier, offsetof(FunctionRNA, identifier)); if (func) { return func; } -- cgit v1.2.3 From 6293cf61312763152b00cb4f588061f7b281caf7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 12 Aug 2021 20:32:37 +1000 Subject: Fix T90630: Crash loading certain user preferences Clearing the window was done in wm_file_read_post which was deferred. This was needed as it left the context in an invalid state where the window was set but the screen wasn't. Crashing when setting up keymaps that attempted to access the scene from the window in the property update function. Regression in 497bc4d19977abc7b9e2c0f5024a23057e680954 --- source/blender/windowmanager/intern/wm_files.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 21c16e94097..b53ad0ee927 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1343,6 +1343,9 @@ void wm_homefile_read_ex(bContext *C, else { *r_params_file_read_post = MEM_mallocN(sizeof(struct wmFileReadPost_Params), __func__); **r_params_file_read_post = params_file_read_post; + + /* Match #wm_file_read_post which leaves the window cleared too. */ + CTX_wm_window_set(C, NULL); } } } -- cgit v1.2.3 From d6891d9bee2bd2073cb45e1ac9a04b2f03f05a9a Mon Sep 17 00:00:00 2001 From: Henrik Dick Date: Thu, 12 Aug 2021 14:22:19 +0200 Subject: Add Extras Dropdown Menu to Constraints Add Apply Constraint, Duplicate Constraint, and Copy To Selected operators, and include them in a menu similar to the menu for modifiers. The shortcuts in the extras menu are also matched to modifiers. All the here added operators are intended to work exactly like the analogous ones for modifiers. That means the apply operator should apply a constraint as if it was first in the list, just like modifiers do. I have added the same warning message as for modifiers when that happens. The decision to use this approach of appling the constraint as if it was first, was made for consistency with modifiers. People are already used to how it works there. Is also provides more intricate control over the applied transforms, then just applying all constraints up to that one. Apply all constraints is already kinda implemented in Bake Animation. Reviewed By: HooglyBoogly, sybren, #user_interface Differential Revision: https://developer.blender.org/D10914 --- source/blender/blenkernel/BKE_constraint.h | 22 ++ source/blender/blenkernel/intern/constraint.c | 105 +++++++ .../blender/draw/engines/overlay/overlay_extra.c | 3 +- .../editors/interface/interface_templates.c | 94 +++++- source/blender/editors/object/object_constraint.c | 324 ++++++++++++++++++++- source/blender/editors/object/object_intern.h | 3 + source/blender/editors/object/object_ops.c | 3 + source/blender/makesrna/intern/rna_constraint.c | 6 + 8 files changed, 540 insertions(+), 20 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 575df93a9fc..784b395dfa5 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -192,6 +192,28 @@ bool BKE_constraint_remove_ex(ListBase *list, bool clear_dep); bool BKE_constraint_remove(ListBase *list, struct bConstraint *con); +bool BKE_constraint_apply_for_object(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct bConstraint *con); +bool BKE_constraint_apply_and_remove_for_object(struct Depsgraph *depsgraph, + struct Scene *scene, + ListBase /*bConstraint*/ *constraints, + struct Object *ob, + struct bConstraint *con); + +bool BKE_constraint_apply_for_pose(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct bPoseChannel *pchan, + struct bConstraint *con); +bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph, + struct Scene *scene, + ListBase /*bConstraint*/ *constraints, + struct Object *ob, + struct bConstraint *con, + struct bPoseChannel *pchan); + void BKE_constraint_panel_expand(struct bConstraint *con); /* Constraints + Proxies function prototypes */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 0da29ded13d..4b26022039e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5677,6 +5677,111 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool return false; } +/* Apply the specified constraint in the given constraint stack */ +bool BKE_constraint_apply_for_object(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + bConstraint *con) +{ + if (!con) { + return false; + } + + const float ctime = BKE_scene_frame_get(scene); + + bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob)); + ListBase single_con = {new_con, new_con}; + + bConstraintOb *cob = BKE_constraints_make_evalob( + depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + /* Undo the effect of the current constraint stack evaluation. */ + mul_m4_m4m4(cob->matrix, ob->constinv, cob->matrix); + + /* Evaluate single constraint. */ + BKE_constraints_solve(depsgraph, &single_con, cob, ctime); + /* Copy transforms back. This will leave the object in a bad state + * as ob->constinv will be wrong until next evaluation. */ + BKE_constraints_clear_evalob(cob); + + /* Free the copied constraint. */ + BKE_constraint_free_data(new_con); + BLI_freelinkN(&single_con, new_con); + + /* Apply transform from matrix. */ + BKE_object_apply_mat4(ob, ob->obmat, true, true); + + return true; +} + +bool BKE_constraint_apply_and_remove_for_object(Depsgraph *depsgraph, + Scene *scene, + ListBase /*bConstraint*/ *constraints, + Object *ob, + bConstraint *con) +{ + if (!BKE_constraint_apply_for_object(depsgraph, scene, ob, con)) { + return false; + } + + return BKE_constraint_remove_ex(constraints, ob, con, true); +} + +bool BKE_constraint_apply_for_pose( + Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + if (!con) { + return false; + } + + const float ctime = BKE_scene_frame_get(scene); + + bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob)); + ListBase single_con; + single_con.first = new_con; + single_con.last = new_con; + + float vec[3]; + copy_v3_v3(vec, pchan->pose_mat[3]); + + bConstraintOb *cob = BKE_constraints_make_evalob( + depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); + /* Undo the effects of currently applied constraints. */ + mul_m4_m4m4(cob->matrix, pchan->constinv, cob->matrix); + /* Evaluate single constraint. */ + BKE_constraints_solve(depsgraph, &single_con, cob, ctime); + BKE_constraints_clear_evalob(cob); + + /* Free the copied constraint. */ + BKE_constraint_free_data(new_con); + BLI_freelinkN(&single_con, new_con); + + /* Prevent constraints breaking a chain. */ + if (pchan->bone->flag & BONE_CONNECTED) { + copy_v3_v3(pchan->pose_mat[3], vec); + } + + /* Apply transform from matrix. */ + float mat[4][4]; + BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, mat); + BKE_pchan_apply_mat4(pchan, mat, true); + + return true; +} + +bool BKE_constraint_apply_and_remove_for_pose(Depsgraph *depsgraph, + Scene *scene, + ListBase /*bConstraint*/ *constraints, + Object *ob, + bConstraint *con, + bPoseChannel *pchan) +{ + if (!BKE_constraint_apply_for_pose(depsgraph, scene, ob, pchan, con)) { + return false; + } + + return BKE_constraint_remove_ex(constraints, ob, con, true); +} + void BKE_constraint_panel_expand(bConstraint *con) { con->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT; diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index f5be9c846d1..2a9080eb217 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1357,7 +1357,8 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, } } } - BKE_constraints_clear_evalob(cob); + /* NOTE: Don't use BKE_constraints_clear_evalob here as that will reset ob->constinv. */ + MEM_freeN(cob); } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 766840909cc..47ff0c9fd3c 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2621,6 +2621,72 @@ static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v) ED_object_constraint_active_set(ob_v, con_v); } +static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v) +{ + PointerRNA op_ptr; + uiLayout *row; + bConstraint *con = (bConstraint *)con_v; + + PointerRNA ptr; + Object *ob = ED_object_active_context(C); + + RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr); + uiLayoutSetContextPointer(layout, "constraint", &ptr); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiLayoutSetUnitsX(layout, 4.0f); + + /* Apply. */ + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), + ICON_CHECKMARK, + "CONSTRAINT_OT_apply"); + + /* Duplicate. */ + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"), + ICON_DUPLICATE, + "CONSTRAINT_OT_copy"); + + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"), + 0, + "CONSTRAINT_OT_copy_to_selected"); + + uiItemS(layout); + + /* Move to first. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "CONSTRAINT_OT_move_to_index", + IFACE_("Move to First"), + ICON_TRIA_UP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", 0); + if (!con->prev) { + uiLayoutSetEnabled(row, false); + } + + /* Move to last. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "CONSTRAINT_OT_move_to_index", + IFACE_("Move to Last"), + ICON_TRIA_DOWN, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + ListBase *constraint_list = ED_object_constraint_list_from_constraint(ob, con, NULL); + RNA_int_set(&op_ptr, "index", BLI_listbase_count(constraint_list) - 1); + if (!con->next) { + uiLayoutSetEnabled(row, false); + } +} + static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) { bPoseChannel *pchan = BKE_pose_channel_active(ob); @@ -2652,11 +2718,13 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co UI_block_emboss_set(block, UI_EMBOSS); + uiLayout *row = uiLayoutRow(layout, true); + if (proxy_protected == 0) { - uiItemR(layout, &ptr, "name", 0, "", ICON_NONE); + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); } else { - uiItemL(layout, con->name, ICON_NONE); + uiItemL(row, con->name, ICON_NONE); } /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */ @@ -2697,22 +2765,22 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co UI_block_emboss_set(block, UI_EMBOSS); } else { - /* enabled */ - UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); - uiItemR(layout, &ptr, "mute", 0, "", 0); - UI_block_emboss_set(block, UI_EMBOSS); + /* Enabled eye icon. */ + uiItemR(row, &ptr, "enabled", 0, "", ICON_NONE); - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + /* Extra operators menu. */ + uiItemMenuF(row, "", ICON_DOWNARROW_HLT, constraint_ops_extra_draw, con); /* Close 'button' - emboss calls here disable drawing of 'button' behind X */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiItemO(layout, "", ICON_X, "CONSTRAINT_OT_delete"); - UI_block_emboss_set(block, UI_EMBOSS); - - /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */ - uiItemS(layout); + sub = uiLayoutRow(row, false); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + uiLayoutSetOperatorContext(sub, WM_OP_INVOKE_DEFAULT); + uiItemO(sub, "", ICON_X, "CONSTRAINT_OT_delete"); } + /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */ + uiItemS(layout); + /* Set but-locks for protected settings (magic numbers are used here!) */ if (proxy_protected) { UI_block_lock_set(block, true, TIP_("Cannot edit Proxy-Protected Constraint")); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 3d0213f1830..e0419e0a4cc 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1483,13 +1483,11 @@ static int constraint_delete_exec(bContext *C, wmOperator *op) /* free the constraint */ if (BKE_constraint_remove_ex(lb, ob, con, true)) { - /* there's no active constraint now, so make sure this is the case */ - BKE_constraints_active_set(&ob->constraints, NULL); /* needed to set the flags on posebones correctly */ ED_object_constraint_update(bmain, ob); /* relations */ - DEG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(bmain); /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); @@ -1507,10 +1505,10 @@ static int constraint_delete_exec(bContext *C, wmOperator *op) static int constraint_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - if (edit_constraint_invoke_properties(C, op, event, &retval)) { - return constraint_delete_exec(C, op); + if (!edit_constraint_invoke_properties(C, op, event, &retval)) { + return OPERATOR_CANCELLED; } - return OPERATOR_CANCELLED; + return constraint_delete_exec(C, op); } void CONSTRAINT_OT_delete(wmOperatorType *ot) @@ -1533,6 +1531,320 @@ void CONSTRAINT_OT_delete(wmOperatorType *ot) /** \} */ +/* ------------------------------------------------------------------- */ +/** \name Apply Constraint Operator + * \{ */ + +static int constraint_apply_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(C, op, ob, 0); + bPoseChannel *pchan; + ListBase *constraints = ED_object_constraint_list_from_constraint(ob, con, &pchan); + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, con->name); + const bool is_first_constraint = con != constraints->first; + + /* Copy the constraint. */ + bool success; + if (pchan) { + success = BKE_constraint_apply_and_remove_for_pose( + depsgraph, scene, constraints, ob, con, pchan); + } + else { + success = BKE_constraint_apply_and_remove_for_object(depsgraph, scene, constraints, ob, con); + } + + if (!success) { + /* Couldn't remove due to some invalid data. */ + return OPERATOR_CANCELLED; + } + + /* Update for any children that may get moved. */ + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + + /* Needed to set the flags on posebones correctly. */ + ED_object_constraint_update(bmain, ob); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + if (pchan) { + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + } + else { + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); + } + + if (RNA_boolean_get(op->ptr, "report")) { + if (is_first_constraint) { + BKE_report(op->reports, + RPT_INFO, + "Applied constraint was not first, result may not be as expected"); + } + else { + /* Only add this report if the operator didn't cause another one. The purpose here is + * to alert that something happened, and the previous report will do that anyway. */ + BKE_reportf(op->reports, RPT_INFO, "Applied constraint: %s", name); + } + } + + return OPERATOR_FINISHED; +} + +static int constraint_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (!edit_constraint_invoke_properties(C, op, event, &retval)) { + return OPERATOR_CANCELLED; + } + return constraint_apply_exec(C, op); +} + +void CONSTRAINT_OT_apply(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Apply Constraint"; + ot->idname = "CONSTRAINT_OT_apply"; + ot->description = "Apply constraint and remove from the stack"; + + /* callbacks */ + ot->invoke = constraint_apply_invoke; + ot->exec = constraint_apply_exec; + ot->poll = edit_constraint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); + edit_constraint_report_property(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Copy Constraint Operator + * \{ */ + +static int constraint_copy_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(C, op, ob, 0); + bPoseChannel *pchan; + ListBase *constraints = ED_object_constraint_list_from_constraint(ob, con, &pchan); + + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, con->name); + + /* Copy the constraint. */ + bConstraint *copy_con; + if (pchan) { + copy_con = BKE_constraint_copy_for_pose(ob, pchan, con); + } + else { + copy_con = BKE_constraint_copy_for_object(ob, con); + } + + if (!copy_con) { + /* Couldn't remove due to some invalid data. */ + return OPERATOR_CANCELLED; + } + /* Move constraint to correct position. */ + const int new_index = BLI_findindex(constraints, con) + 1; + const int current_index = BLI_findindex(constraints, copy_con); + BLI_assert(new_index >= 0); + BLI_assert(current_index >= 0); + BLI_listbase_link_move(constraints, copy_con, new_index - current_index); + + /* Needed to set the flags on posebones correctly. */ + ED_object_constraint_update(bmain, ob); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob); + + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Copied constraint: %s", name); + } + + return OPERATOR_FINISHED; +} + +static int constraint_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (!edit_constraint_invoke_properties(C, op, event, &retval)) { + return OPERATOR_CANCELLED; + } + return constraint_copy_exec(C, op); +} + +void CONSTRAINT_OT_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Constraint"; + ot->idname = "CONSTRAINT_OT_copy"; + ot->description = "Duplicate constraint at the same position in the stack"; + + /* callbacks */ + ot->invoke = constraint_copy_invoke; + ot->exec = constraint_copy_exec; + ot->poll = edit_constraint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); + edit_constraint_report_property(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Copy Constraint To Selected Operator + * \{ */ + +static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *obact = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(C, op, obact, 0); + bPoseChannel *pchan; + ED_object_constraint_list_from_constraint(obact, con, &pchan); + + if (pchan) { + /* Don't do anything if bone doesn't exist or doesn't have any constraints. */ + if (pchan->constraints.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No constraints for copying"); + return OPERATOR_CANCELLED; + } + + Object *prev_ob = NULL; + + /* Copy all constraints from active posebone to all selected posebones. */ + CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) { + /* If we're not handling the object we're copying from, copy all constraints over. */ + if (pchan == chan) { + continue; + } + + BKE_constraint_copy_for_pose(ob, chan, con); + /* Update flags (need to add here, not just copy). */ + chan->constflag |= pchan->constflag; + + if (prev_ob == ob) { + continue; + } + + BKE_pose_tag_recalc(bmain, ob->pose); + DEG_id_tag_update((ID *)ob, ID_RECALC_GEOMETRY); + prev_ob = ob; + } + CTX_DATA_END; + } + else { + /* Copy all constraints from active object to all selected objects. */ + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { + /* If we're not handling the object we're copying from, copy all constraints over. */ + if (obact == ob) { + continue; + } + + BKE_constraint_copy_for_object(ob, con); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); + } + CTX_DATA_END; + } + + /* Force depsgraph to get recalculated since new relationships added. */ + DEG_relations_tag_update(bmain); + + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL); + + return OPERATOR_FINISHED; +} + +static int constraint_copy_to_selected_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (!edit_constraint_invoke_properties(C, op, event, &retval)) { + return retval; + } + return constraint_copy_to_selected_exec(C, op); +} + +static bool constraint_copy_to_selected_poll(bContext *C) +{ + PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); + Object *obact = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); + bConstraint *con = ptr.data; + bPoseChannel *pchan; + ED_object_constraint_list_from_constraint(obact, con, &pchan); + + if (pchan) { + bool found = false; + CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, UNUSED(ob)) { + if (pchan != chan) { + /** NOTE: Can not return here, because CTX_DATA_BEGIN_WITH_ID allocated + * a list that needs to be freed by CTX_DATA_END. */ + found = true; + break; + } + } + CTX_DATA_END; + if (found) { + return true; + } + + CTX_wm_operator_poll_msg_set(C, "No other bones are selected"); + return false; + } + + if (!obact) { + CTX_wm_operator_poll_msg_set(C, "No selected object to copy from"); + return false; + } + + bool found = false; + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob != obact) { + /** NOTE: Can not return here, because CTX_DATA_BEGIN allocated + * a list that needs to be freed by CTX_DATA_END. */ + found = true; + break; + } + } + CTX_DATA_END; + if (found) { + return true; + } + + CTX_wm_operator_poll_msg_set(C, "No other objects are selected"); + return false; +} + +void CONSTRAINT_OT_copy_to_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Copy Constraint To Selected"; + ot->idname = "CONSTRAINT_OT_copy_to_selected"; + ot->description = "Copy constraint to other selected objects/bones"; + + /* api callbacks */ + ot->exec = constraint_copy_to_selected_exec; + ot->invoke = constraint_copy_to_selected_invoke; + ot->poll = constraint_copy_to_selected_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); +} + +/** \} */ + /* ------------------------------------------------------------------- */ /** \name Move Down Constraint Operator * \{ */ diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 6299fdcc7f7..10e016738d0 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -226,6 +226,9 @@ void POSE_OT_ik_add(struct wmOperatorType *ot); void POSE_OT_ik_clear(struct wmOperatorType *ot); void CONSTRAINT_OT_delete(struct wmOperatorType *ot); +void CONSTRAINT_OT_apply(struct wmOperatorType *ot); +void CONSTRAINT_OT_copy(struct wmOperatorType *ot); +void CONSTRAINT_OT_copy_to_selected(struct wmOperatorType *ot); void CONSTRAINT_OT_move_up(struct wmOperatorType *ot); void CONSTRAINT_OT_move_to_index(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a438c760d3b..c1928cf7f8a 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -183,6 +183,9 @@ void ED_operatortypes_object(void) WM_operatortype_append(POSE_OT_ik_add); WM_operatortype_append(POSE_OT_ik_clear); WM_operatortype_append(CONSTRAINT_OT_delete); + WM_operatortype_append(CONSTRAINT_OT_apply); + WM_operatortype_append(CONSTRAINT_OT_copy); + WM_operatortype_append(CONSTRAINT_OT_copy_to_selected); WM_operatortype_append(CONSTRAINT_OT_move_up); WM_operatortype_append(CONSTRAINT_OT_move_down); WM_operatortype_append(CONSTRAINT_OT_move_to_index); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index e36d052d27c..5968c8bac8f 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -3509,6 +3509,12 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONSTRAINT_OFF); + RNA_def_property_ui_text(prop, "Enabled", "Use the results of this constraint"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1); + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); RNA_def_property_boolean_sdna(prop, NULL, "ui_expand_flag", 0); -- cgit v1.2.3 From dc8844f8ef6a5cfa2be1035162d39e6d83c83d7c Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Fri, 4 Jun 2021 16:39:12 +0200 Subject: Fix T88498: 'Clear Parent' does not clear parent_bone Clearing the parent from the UI using the X (or from python) clears the `parsubstr` and set `partype` back to `PAROBJECT`. Using the Clear Parent operator would leave the `parsubstr` (and thus `parent_bone`) untouched even though this operator claims to "clear parenting relationship completely" (it also removes parent deform modifiers for example). So now, also clear `parsubstr` and set back to `PAROBJECT` [which is default]. Maniphest Tasks: T88498 Differential Revision: https://developer.blender.org/D11503 --- source/blender/editors/object/object_relations.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index c0b954f3cff..ec72ff11683 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -570,6 +570,8 @@ void ED_object_parent_clear(Object *ob, const int type) /* clear parenting relationship completely */ ob->parent = NULL; + ob->partype = PAROBJECT; + ob->parsubstr[0] = 0; break; } case CLEAR_PARENT_KEEP_TRANSFORM: { -- cgit v1.2.3 From 333c3c92ab83c1b18e05a0e765d72f66fc5a5466 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Fri, 30 Jul 2021 11:58:02 +0200 Subject: Fix T89805: NLA crash without active track Was reported for a file which does not have an active track set in AnimData even though it was in strip twek mode (but this was accessed in is_nlatrack_evaluatable()). Root cause for this is not totally clear, but I assume the situation is described as part T87681 (and is fixed in D11052). This patch here just prevents the crash for files that are already in the borked state. Reviewers: sybren Maniphest Tasks: T89805 Differential Revision: https://developer.blender.org/D12085 --- source/blender/blenkernel/intern/anim_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 10a865880f2..92b0db5b214 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -2671,7 +2671,7 @@ static void animsys_create_action_track_strip(const AnimData *adt, static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt) { /* Skip disabled tracks unless it contains the tweaked strip. */ - const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) && + const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) && adt->act_track && (nlt->index == adt->act_track->index); if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) { return false; -- cgit v1.2.3 From 3930b8c69e274df4aab91f7469510c8636a96cbf Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 21 Apr 2021 18:08:50 +0200 Subject: Fix NLA action cannot be unlinked in certain cases The poll for unlinking calls `nla_panel_context` without providing an adt pointer, and there is a check for this pointer in `nla_panel_context` leading to never returning true if it is not provided. (this is fine if there are tracks already, poll would succeed in this case, `nla_panel_context` goes a different code path then) Same call to `nla_panel_context` is also done in the beginning of the corresponding unlink exec function (but this time providing the pointer because it is used later), so it makes sense to do the same thing in the poll function. Equal check is also done in the panel poll function, so now these are all in sync. Part of T87681. Maniphest Tasks: T87681 Differential Revision: https://developer.blender.org/D11041 --- source/blender/editors/space_nla/nla_channels.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 0498964c549..1b87a8c6b9d 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -562,7 +562,8 @@ void NLA_OT_action_pushdown(wmOperatorType *ot) static bool nla_action_unlink_poll(bContext *C) { if (ED_operator_nla_active(C)) { - return nla_panel_context(C, NULL, NULL, NULL); + PointerRNA adt_ptr; + return (nla_panel_context(C, &adt_ptr, NULL, NULL) && (adt_ptr.data != NULL)); } /* something failed... */ -- cgit v1.2.3 From f801d40dafc06be2c0827e1b858c84800f4ddad8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 01:00:50 +1000 Subject: Fix T89241: 3D Text "Scale to Fit" wraps onto the second line Disable wrapping when "scale to fit" is used, assert the error is small so an invalid scale-to-fit value wont go by unnoticed. --- source/blender/blenkernel/intern/font.c | 95 +++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 35 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 37fc14911fe..de838f1b3cd 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -715,6 +715,11 @@ typedef struct VFontToCurveIter { float max; } bisect; bool ok; + /** + * Disables checking if word wrapping is needed to fit the text-box width. + * Currently only used when scale-to-fit is enabled. + */ + bool word_wrap; int status; } VFontToCurveIter; @@ -777,6 +782,7 @@ static bool vfont_to_curve(Object *ob, char32_t ascii; bool ok = false; const float font_size = cu->fsize * iter_data->scale_to_fit; + const bool word_wrap = iter_data->word_wrap; const float xof_scale = cu->xof / font_size; const float yof_scale = cu->yof / font_size; int last_line = -1; @@ -947,43 +953,59 @@ static bool vfont_to_curve(Object *ob, twidth = char_width(cu, che, info); - /* Calculate positions */ - if ((tb_scale.w != 0.0f) && (ct->dobreak == 0) && - (((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.w)) { - // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]); - for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) { - bool dobreak = false; - if (ELEM(mem[j], ' ', '-')) { - ct -= (i - (j - 1)); - cnr -= (i - (j - 1)); - if (mem[j] == ' ') { - wsnr--; + /* Calculate positions. */ + + if ((tb_scale.w != 0.0f) && (ct->dobreak == 0)) { /* May need wrapping. */ + const float x_available = xof_scale + tb_scale.w; + const float x_used = (xof - tb_scale.x) + twidth; + + if (word_wrap == false) { + /* When scale to fit is used, don't do any wrapping. + * + * Floating precision error can cause the text to be slightly larger. + * Assert this is a small value as large values indicate incorrect + * calculations with scale-to-fit which shouldn't be ignored. See T89241. */ + if (x_used > x_available) { + BLI_assert_msg(compare_ff_relative(x_used, x_available, FLT_EPSILON, 64), + "VFontToCurveIter.scale_to_fit not set correctly!"); + } + } + else if (x_used > x_available) { + // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]); + for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) { + bool dobreak = false; + if (ELEM(mem[j], ' ', '-')) { + ct -= (i - (j - 1)); + cnr -= (i - (j - 1)); + if (mem[j] == ' ') { + wsnr--; + } + if (mem[j] == '-') { + wsnr++; + } + i = j - 1; + xof = ct->xof; + ct[1].dobreak = 1; + custrinfo[i + 1].flag |= CU_CHINFO_WRAP; + dobreak = true; } - if (mem[j] == '-') { - wsnr++; + else if (chartransdata[j].dobreak) { + // CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]); + ct->dobreak = 1; + custrinfo[i + 1].flag |= CU_CHINFO_WRAP; + ct -= 1; + cnr -= 1; + i--; + xof = ct->xof; + dobreak = true; } - i = j - 1; - xof = ct->xof; - ct[1].dobreak = 1; - custrinfo[i + 1].flag |= CU_CHINFO_WRAP; - dobreak = true; - } - else if (chartransdata[j].dobreak) { - // CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]); - ct->dobreak = 1; - custrinfo[i + 1].flag |= CU_CHINFO_WRAP; - ct -= 1; - cnr -= 1; - i--; - xof = ct->xof; - dobreak = true; - } - if (dobreak) { - if (tb_scale.h == 0.0f) { - /* NOTE: If underlined text is truncated away, the extra space is also truncated. */ - custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW; + if (dobreak) { + if (tb_scale.h == 0.0f) { + /* NOTE: If underlined text is truncated away, the extra space is also truncated. */ + custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW; + } + goto makebreak; } - goto makebreak; } } } @@ -1545,6 +1567,7 @@ static bool vfont_to_curve(Object *ob, const float total_text_height = lnr * linedist; iter_data->scale_to_fit = tb_scale.h / total_text_height; iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; + iter_data->word_wrap = false; } } else if (tb_scale.h == 0.0f) { @@ -1552,10 +1575,10 @@ static bool vfont_to_curve(Object *ob, if (longest_line_length > tb_scale.w) { /* We make sure longest line before it broke can fit here. */ float scale_to_fit = tb_scale.w / longest_line_length; - scale_to_fit -= FLT_EPSILON; iter_data->scale_to_fit = scale_to_fit; iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; + iter_data->word_wrap = false; } } } @@ -1616,6 +1639,7 @@ static bool vfont_to_curve(Object *ob, else { iter_data->scale_to_fit = iter_data->bisect.min; iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; + iter_data->word_wrap = false; } } } @@ -1685,6 +1709,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, VFontToCurveIter data = { .iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS, .scale_to_fit = 1.0f, + .word_wrap = true, .ok = true, .status = VFONT_TO_CURVE_INIT, }; -- cgit v1.2.3 From e0fd5fef1236eff14d1c6dc1c7f6ba27a9ff5787 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 12 Aug 2021 17:36:37 +0200 Subject: Geometry Nodes: tag normals dirty after join Under some circumstances the normals were not tagged dirty even though they are. --- source/blender/blenkernel/intern/geometry_set_instances.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 90a97264c8f..32a65ab47bf 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -491,6 +491,10 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span Date: Thu, 12 Aug 2021 14:12:14 -0500 Subject: Cleanup: Remove unused includes I noticed this file was recompiling when adding a node. --- source/blender/makesrna/intern/rna_curveprofile.c | 27 ----------------------- 1 file changed, 27 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_curveprofile.c b/source/blender/makesrna/intern/rna_curveprofile.c index b3ab8cc15a2..66c0fc72c7a 100644 --- a/source/blender/makesrna/intern/rna_curveprofile.c +++ b/source/blender/makesrna/intern/rna_curveprofile.c @@ -23,9 +23,6 @@ #include "DNA_curve_types.h" #include "DNA_curveprofile_types.h" -#include "DNA_texture_types.h" - -#include "BLI_utildefines.h" #include "RNA_define.h" #include "rna_internal.h" @@ -37,31 +34,7 @@ # include "RNA_access.h" -# include "DNA_image_types.h" -# include "DNA_material_types.h" -# include "DNA_movieclip_types.h" -# include "DNA_node_types.h" -# include "DNA_object_types.h" -# include "DNA_particle_types.h" -# include "DNA_sequence_types.h" - -# include "MEM_guardedalloc.h" - -# include "BKE_colorband.h" # include "BKE_curveprofile.h" -# include "BKE_image.h" -# include "BKE_linestyle.h" -# include "BKE_movieclip.h" -# include "BKE_node.h" - -# include "DEG_depsgraph.h" - -# include "ED_node.h" - -# include "IMB_colormanagement.h" -# include "IMB_imbuf.h" - -# include "SEQ_sequencer.h" /** * Set both handle types for all selected points in the profile-- faster than changing types -- cgit v1.2.3 From 399b6ec76c80a8f343747a0459bb3d3df514555f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 09:27:29 +1000 Subject: Mesh: optimize normal calculation Optimize mesh normal calculation. - Remove the intermediate `lnors_weighted` array, accumulate directly into the normal array using a spin-lock for thread safety. - Remove single threaded iteration over loops (normal calculation is now fully multi-threaded). - Remove stack array (alloca) for pre-calculating edge-directions. Summary of Performance Characteristics: - The largest gains are for single high poly meshes, with isolated normal-calculation benchmarks of meshes over ~1.5 million showing 2x+ speedup, ~25 million polygons are ~2.85x faster. - Single lower poly meshes (250k polys) can be ~2x slower. Since these meshes aren't normally a bottleneck, and this problem isn't noticeable on large scenes, we considered the performance trade-off reasonable. - The performance difference reduces with larger scenes, tests with production files from "Sprite Fight" showing the same or slightly better overall performance. NOTE: tested on a AMD Ryzen TR 3970X 32-Core. For more details & benchmarking scripts, see the patch description. Reviewed By: mont29 Ref D11993 --- source/blender/blenkernel/intern/mesh_normals.cc | 135 ++++++++++++++--------- 1 file changed, 82 insertions(+), 53 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 6bd08b3dbe0..b86332097fa 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -50,6 +50,8 @@ #include "BKE_global.h" #include "BKE_mesh.h" +#include "atomic_ops.h" + // #define DEBUG_TIME #ifdef DEBUG_TIME @@ -59,6 +61,46 @@ static CLG_LogRef LOG = {"bke.mesh_normals"}; +/* -------------------------------------------------------------------- */ +/** \name Private Utility Functions + * \{ */ + +/** + * A thread-safe version of #add_v3_v3 that uses a spin-lock. + * + * \note Avoid using this when the chance of contention is high. + */ +static void add_v3_v3_atomic(float r[3], const float a[3]) +{ +#define FLT_EQ_NONAN(_fa, _fb) (*((const uint32_t *)&_fa) == *((const uint32_t *)&_fb)) + + float virtual_lock = r[0]; + while (true) { + /* This loops until following conditions are met: + * - `r[0]` has same value as virtual_lock (i.e. it did not change since last try). + * - `r[0]` was not `FLT_MAX`, i.e. it was not locked by another thread. */ + const float test_lock = atomic_cas_float(&r[0], virtual_lock, FLT_MAX); + if (_ATOMIC_LIKELY(FLT_EQ_NONAN(test_lock, virtual_lock) && (test_lock != FLT_MAX))) { + break; + } + virtual_lock = test_lock; + } + virtual_lock += a[0]; + r[1] += a[1]; + r[2] += a[2]; + + /* Second atomic operation to 'release' + * our lock on that vector and set its first scalar value. */ + /* Note that we do not need to loop here, since we 'locked' `r[0]`, + * nobody should have changed it in the mean time. */ + virtual_lock = atomic_cas_float(&r[0], FLT_MAX, virtual_lock); + BLI_assert(virtual_lock == FLT_MAX); + +#undef FLT_EQ_NONAN +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Mesh Normal Calculation * \{ */ @@ -210,7 +252,6 @@ struct MeshCalcNormalsData { const MLoop *mloop; MVert *mverts; float (*pnors)[3]; - float (*lnors_weighted)[3]; float (*vnors)[3]; }; @@ -224,65 +265,65 @@ static void mesh_calc_normals_poly_cb(void *__restrict userdata, BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]); } -static void mesh_calc_normals_poly_prepare_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict UNUSED(tls)) +static void mesh_calc_normals_poly_and_accum_cb(void *__restrict userdata, + const int pidx, + const TaskParallelTLS *__restrict UNUSED(tls)) { - MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; + const MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; const MPoly *mp = &data->mpolys[pidx]; const MLoop *ml = &data->mloop[mp->loopstart]; const MVert *mverts = data->mverts; + float(*vnors)[3] = data->vnors; float pnor_temp[3]; float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; - float(*lnors_weighted)[3] = data->lnors_weighted; - const int nverts = mp->totloop; - float(*edgevecbuf)[3] = (float(*)[3])BLI_array_alloca(edgevecbuf, (size_t)nverts); + const int i_end = mp->totloop - 1; /* Polygon Normal and edge-vector */ /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ { - int i_prev = nverts - 1; - const float *v_prev = mverts[ml[i_prev].v].co; - const float *v_curr; - zero_v3(pnor); /* Newell's Method */ - for (int i = 0; i < nverts; i++) { - v_curr = mverts[ml[i].v].co; - add_newell_cross_v3_v3v3(pnor, v_prev, v_curr); - - /* Unrelated to normalize, calculate edge-vector */ - sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr); - normalize_v3(edgevecbuf[i_prev]); - i_prev = i; - - v_prev = v_curr; + const float *v_curr = mverts[ml[i_end].v].co; + for (int i_next = 0; i_next <= i_end; i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + add_newell_cross_v3_v3v3(pnor, v_curr, v_next); + v_curr = v_next; } if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { pnor[2] = 1.0f; /* other axes set to 0.0 */ } } - /* accumulate angle weighted face normal */ - /* inline version of #accumulate_vertex_normals_poly_v3, - * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */ + /* Accumulate angle weighted face normal into the vertex normal. */ + /* inline version of #accumulate_vertex_normals_poly_v3. */ { - const float *prev_edge = edgevecbuf[nverts - 1]; - - for (int i = 0; i < nverts; i++) { - const int lidx = mp->loopstart + i; - const float *cur_edge = edgevecbuf[i]; - - /* calculate angle between the two poly edges incident on - * this vertex */ - const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); + float edvec_prev[3], edvec_next[3], edvec_end[3]; + const float *v_curr = mverts[ml[i_end].v].co; + sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr); + normalize_v3(edvec_prev); + copy_v3_v3(edvec_end, edvec_prev); + + for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + + /* Skip an extra normalization by reusing the first calculated edge. */ + if (i_next != i_end) { + sub_v3_v3v3(edvec_next, v_curr, v_next); + normalize_v3(edvec_next); + } + else { + copy_v3_v3(edvec_next, edvec_end); + } - /* Store for later accumulation */ - mul_v3_v3fl(lnors_weighted[lidx], pnor, fac); + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); + const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; - prev_edge = cur_edge; + add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); + v_curr = v_next; + copy_v3_v3(edvec_prev, edvec_next); } } } @@ -309,7 +350,7 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, const MLoop *mloop, const MPoly *mpolys, - int numLoops, + int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], const bool only_face_normals) @@ -335,8 +376,6 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, } float(*vnors)[3] = r_vertnors; - float(*lnors_weighted)[3] = (float(*)[3])MEM_malloc_arrayN( - (size_t)numLoops, sizeof(*lnors_weighted), __func__); bool free_vnors = false; /* first go through and calculate normals for all the polys */ @@ -353,27 +392,17 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, data.mloop = mloop; data.mverts = mverts; data.pnors = pnors; - data.lnors_weighted = lnors_weighted; data.vnors = vnors; - /* Compute poly normals, and prepare weighted loop normals. */ - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings); - - /* Actually accumulate weighted loop normals into vertex ones. */ - /* Unfortunately, not possible to thread that - * (not in a reasonable, totally lock- and barrier-free fashion), - * since several loops will point to the same vertex... */ - for (int lidx = 0; lidx < numLoops; lidx++) { - add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]); - } + /* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */ + BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_and_accum_cb, &settings); - /* Normalize and validate computed vertex normals. */ + /* Normalize and validate computed vertex normals (`vnors`). */ BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); if (free_vnors) { MEM_freeN(vnors); } - MEM_freeN(lnors_weighted); } void BKE_mesh_ensure_normals(Mesh *mesh) -- cgit v1.2.3 From ed38d0c25da27c8fe6b3db76dbe024f33f82e338 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 13:23:45 +1000 Subject: Cleanup: split BKE_mesh_calc_normals_poly function in two Remove the 'only_face_normals' argument. - BKE_mesh_calc_normals_poly for polygon normals. - BKE_mesh_calc_normals_poly_and_vertex for poly and vertex normals. Order arguments logically: - Pair array and length arguments. - Position normal array arguments (to be filled) last. --- source/blender/blenkernel/BKE_mesh.h | 22 +- source/blender/blenkernel/intern/DerivedMesh.cc | 34 +- source/blender/blenkernel/intern/data_transfer.c | 6 +- source/blender/blenkernel/intern/key.c | 11 +- source/blender/blenkernel/intern/mesh.c | 17 +- source/blender/blenkernel/intern/mesh_mirror.c | 17 +- source/blender/blenkernel/intern/mesh_normals.cc | 427 ++++++++++++--------- source/blender/blenkernel/intern/mesh_remap.c | 12 +- source/blender/editors/mesh/mesh_data.c | 11 +- source/blender/modifiers/intern/MOD_normal_edit.c | 16 +- .../modifiers/intern/MOD_solidify_extrude.c | 6 +- .../modifiers/intern/MOD_solidify_nonmanifold.c | 11 +- .../blender/modifiers/intern/MOD_weighted_normal.c | 4 +- 13 files changed, 308 insertions(+), 286 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index ef1384c804b..4eb3e6a3136 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -305,15 +305,21 @@ void BKE_mesh_calc_normals_mapping_ex(struct MVert *mverts, const int *origIndexFace, float (*r_faceNors)[3], const bool only_face_normals); -void BKE_mesh_calc_normals_poly(struct MVert *mverts, - float (*r_vertnors)[3], - int numVerts, +void BKE_mesh_calc_normals_poly(const struct MVert *mvert, + int mvert_len, const struct MLoop *mloop, - const struct MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const bool only_face_normals); + int mloop_len, + const struct MPoly *mpoly, + int mpoly_len, + float (*r_poly_normals)[3]); +void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert, + int mvert_len, + const struct MLoop *mloop, + int mloop_len, + const struct MPoly *mpolys, + int mpoly_len, + float (*r_poly_normals)[3], + float (*r_vert_normals)[3]); void BKE_mesh_calc_normals(struct Mesh *me); void BKE_mesh_ensure_normals(struct Mesh *me); void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh); diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 4480b0d34fc..59e81938e79 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -816,15 +816,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { float(*polynors)[3] = (float(*)[3])CustomData_add_layer( &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly); - BKE_mesh_calc_normals_poly(mesh_final->mvert, - nullptr, - mesh_final->totvert, - mesh_final->mloop, - mesh_final->mpoly, - mesh_final->totloop, - mesh_final->totpoly, - polynors, - false); + BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert, + mesh_final->totvert, + mesh_final->mloop, + mesh_final->totloop, + mesh_final->mpoly, + mesh_final->totpoly, + polynors, + nullptr); } } @@ -1536,15 +1535,14 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { float(*polynors)[3] = (float(*)[3])CustomData_add_layer( &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly); - BKE_mesh_calc_normals_poly(mesh_final->mvert, - nullptr, - mesh_final->totvert, - mesh_final->mloop, - mesh_final->mpoly, - mesh_final->totloop, - mesh_final->totpoly, - polynors, - false); + BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert, + mesh_final->totvert, + mesh_final->mloop, + mesh_final->totloop, + mesh_final->mpoly, + mesh_final->totpoly, + polynors, + nullptr); } } diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 605061570b8..b83621e8b79 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -301,14 +301,12 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, } if (dirty_nors_dst || do_poly_nors_dst) { BKE_mesh_calc_normals_poly(verts_dst, - NULL, num_verts_dst, loops_dst, - polys_dst, num_loops_dst, + polys_dst, num_polys_dst, - poly_nors_dst, - true); + poly_nors_dst); } /* Cache loop nors into a temp CDLayer. */ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 0f8c9bad798..724216bee6c 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -2281,15 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb, r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__); free_polynors = true; } - BKE_mesh_calc_normals_poly(me.mvert, - r_vertnors, - me.totvert, - me.mloop, - me.mpoly, - me.totloop, - me.totpoly, - r_polynors, - false); + BKE_mesh_calc_normals_poly_and_vertex( + me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors); if (r_loopnors) { short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */ diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 4aef0f346c3..b32d58de1e2 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1890,15 +1890,14 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac } else { polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); - BKE_mesh_calc_normals_poly(mesh->mvert, - NULL, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - polynors, - false); + BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + polynors, + NULL); free_polynors = true; } diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index 9aeaa1ada52..b20d81e7b9c 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -393,15 +393,14 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* calculate custom normals into loop_normals, then mirror first half into second half */ - BKE_mesh_calc_normals_poly(result->mvert, - NULL, - result->totvert, - result->mloop, - result->mpoly, - totloop, - totpoly, - poly_normals, - false); + BKE_mesh_calc_normals_poly_and_vertex(result->mvert, + result->totvert, + result->mloop, + totloop, + result->mpoly, + totpoly, + poly_normals, + NULL); BKE_mesh_normals_loop_split(result->mvert, result->totvert, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index b86332097fa..fe28f10d2db 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -102,7 +102,9 @@ static void add_v3_v3_atomic(float r[3], const float a[3]) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mesh Normal Calculation +/** \name Public Utility Functions + * + * Related to managing normals but not directly related to calculating normals. * \{ */ void BKE_mesh_normals_tag_dirty(Mesh *mesh) @@ -111,6 +113,205 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh) mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Normal Calculation (Polygons) + * \{ */ + +struct MeshCalcNormalsData_Poly { + const MVert *mvert; + const MLoop *mloop; + const MPoly *mpoly; + + /** Polygon normal output. */ + float (*pnors)[3]; +}; + +static void mesh_calc_normals_poly_fn(void *__restrict userdata, + const int pidx, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const MeshCalcNormalsData_Poly *data = (MeshCalcNormalsData_Poly *)userdata; + const MPoly *mp = &data->mpoly[pidx]; + BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mvert, data->pnors[pidx]); +} + +void BKE_mesh_calc_normals_poly(const MVert *mvert, + int UNUSED(mvert_len), + const MLoop *mloop, + int UNUSED(mloop_len), + const MPoly *mpoly, + int mpoly_len, + float (*r_poly_normals)[3]) +{ + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + + BLI_assert((r_poly_normals != nullptr) || (mpoly_len == 0)); + + MeshCalcNormalsData_Poly data = {}; + data.mpoly = mpoly; + data.mloop = mloop; + data.mvert = mvert; + data.pnors = r_poly_normals; + + BLI_task_parallel_range(0, mpoly_len, &data, mesh_calc_normals_poly_fn, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Normal Calculation (Polygons & Vertices) + * + * Implement #BKE_mesh_calc_normals_poly_and_vertex, + * + * Take care making optimizations to this function as improvements to low-poly + * meshes can slow down high-poly meshes. For details on performance, see D11993. + * \{ */ + +struct MeshCalcNormalsData_PolyAndVertex { + /** Write into vertex normals #MVert.no. */ + MVert *mvert; + const MLoop *mloop; + const MPoly *mpoly; + + /** Polygon normal output. */ + float (*pnors)[3]; + /** Vertex normal output (may be freed, copied into #MVert.no). */ + float (*vnors)[3]; +}; + +static void mesh_calc_normals_poly_and_vertex_accum_fn( + void *__restrict userdata, const int pidx, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata; + const MPoly *mp = &data->mpoly[pidx]; + const MLoop *ml = &data->mloop[mp->loopstart]; + const MVert *mverts = data->mvert; + float(*vnors)[3] = data->vnors; + + float pnor_temp[3]; + float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; + + const int i_end = mp->totloop - 1; + + /* Polygon Normal and edge-vector */ + /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ + { + zero_v3(pnor); + /* Newell's Method */ + const float *v_curr = mverts[ml[i_end].v].co; + for (int i_next = 0; i_next <= i_end; i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + add_newell_cross_v3_v3v3(pnor, v_curr, v_next); + v_curr = v_next; + } + if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { + pnor[2] = 1.0f; /* other axes set to 0.0 */ + } + } + + /* Accumulate angle weighted face normal into the vertex normal. */ + /* inline version of #accumulate_vertex_normals_poly_v3. */ + { + float edvec_prev[3], edvec_next[3], edvec_end[3]; + const float *v_curr = mverts[ml[i_end].v].co; + sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr); + normalize_v3(edvec_prev); + copy_v3_v3(edvec_end, edvec_prev); + + for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) { + const float *v_next = mverts[ml[i_next].v].co; + + /* Skip an extra normalization by reusing the first calculated edge. */ + if (i_next != i_end) { + sub_v3_v3v3(edvec_next, v_curr, v_next); + normalize_v3(edvec_next); + } + else { + copy_v3_v3(edvec_next, edvec_end); + } + + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); + const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; + + add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); + v_curr = v_next; + copy_v3_v3(edvec_prev, edvec_next); + } + } +} + +static void mesh_calc_normals_poly_and_vertex_finalize_fn( + void *__restrict userdata, const int vidx, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata; + + MVert *mv = &data->mvert[vidx]; + float *no = data->vnors[vidx]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); +} + +void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert, + const int mvert_len, + const MLoop *mloop, + const int UNUSED(mloop_len), + const MPoly *mpoly, + const int mpoly_len, + float (*r_poly_normals)[3], + float (*r_vert_normals)[3]) +{ + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + + float(*vnors)[3] = r_vert_normals; + bool free_vnors = false; + + /* first go through and calculate normals for all the polys */ + if (vnors == nullptr) { + vnors = (float(*)[3])MEM_calloc_arrayN((size_t)mvert_len, sizeof(*vnors), __func__); + free_vnors = true; + } + else { + memset(vnors, 0, sizeof(*vnors) * (size_t)mvert_len); + } + + MeshCalcNormalsData_PolyAndVertex data = {}; + data.mpoly = mpoly; + data.mloop = mloop; + data.mvert = mvert; + data.pnors = r_poly_normals; + data.vnors = vnors; + + /* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */ + BLI_task_parallel_range( + 0, mpoly_len, &data, mesh_calc_normals_poly_and_vertex_accum_fn, &settings); + + /* Normalize and validate computed vertex normals (`vnors`). */ + BLI_task_parallel_range( + 0, mvert_len, &data, mesh_calc_normals_poly_and_vertex_finalize_fn, &settings); + + if (free_vnors) { + MEM_freeN(vnors); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Normal Calculation + * \{ */ + /** * Call when there are no polygons. */ @@ -212,8 +413,8 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, if (only_face_normals == false) { /* vertex normals are optional, they require some extra calculations, * so make them optional */ - BKE_mesh_calc_normals_poly( - mverts, nullptr, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); + BKE_mesh_calc_normals_poly_and_vertex( + mverts, numVerts, mloop, numLoops, mpolys, numPolys, pnors, nullptr); } else { /* only calc poly normals */ @@ -247,164 +448,6 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, fnors = pnors = nullptr; } -struct MeshCalcNormalsData { - const MPoly *mpolys; - const MLoop *mloop; - MVert *mverts; - float (*pnors)[3]; - float (*vnors)[3]; -}; - -static void mesh_calc_normals_poly_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - const MPoly *mp = &data->mpolys[pidx]; - - BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]); -} - -static void mesh_calc_normals_poly_and_accum_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - const MPoly *mp = &data->mpolys[pidx]; - const MLoop *ml = &data->mloop[mp->loopstart]; - const MVert *mverts = data->mverts; - float(*vnors)[3] = data->vnors; - - float pnor_temp[3]; - float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; - - const int i_end = mp->totloop - 1; - - /* Polygon Normal and edge-vector */ - /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ - { - zero_v3(pnor); - /* Newell's Method */ - const float *v_curr = mverts[ml[i_end].v].co; - for (int i_next = 0; i_next <= i_end; i_next++) { - const float *v_next = mverts[ml[i_next].v].co; - add_newell_cross_v3_v3v3(pnor, v_curr, v_next); - v_curr = v_next; - } - if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { - pnor[2] = 1.0f; /* other axes set to 0.0 */ - } - } - - /* Accumulate angle weighted face normal into the vertex normal. */ - /* inline version of #accumulate_vertex_normals_poly_v3. */ - { - float edvec_prev[3], edvec_next[3], edvec_end[3]; - const float *v_curr = mverts[ml[i_end].v].co; - sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr); - normalize_v3(edvec_prev); - copy_v3_v3(edvec_end, edvec_prev); - - for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) { - const float *v_next = mverts[ml[i_next].v].co; - - /* Skip an extra normalization by reusing the first calculated edge. */ - if (i_next != i_end) { - sub_v3_v3v3(edvec_next, v_curr, v_next); - normalize_v3(edvec_next); - } - else { - copy_v3_v3(edvec_next, edvec_end); - } - - /* Calculate angle between the two poly edges incident on this vertex. */ - const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); - const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; - - add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); - v_curr = v_next; - copy_v3_v3(edvec_prev, edvec_next); - } - } -} - -static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata, - const int vidx, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata; - - MVert *mv = &data->mverts[vidx]; - float *no = data->vnors[vidx]; - - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); -} - -void BKE_mesh_calc_normals_poly(MVert *mverts, - float (*r_vertnors)[3], - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int UNUSED(numLoops), - int numPolys, - float (*r_polynors)[3], - const bool only_face_normals) -{ - float(*pnors)[3] = r_polynors; - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - - if (only_face_normals) { - BLI_assert((pnors != nullptr) || (numPolys == 0)); - BLI_assert(r_vertnors == nullptr); - - MeshCalcNormalsData data; - data.mpolys = mpolys; - data.mloop = mloop; - data.mverts = mverts; - data.pnors = pnors; - - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings); - return; - } - - float(*vnors)[3] = r_vertnors; - bool free_vnors = false; - - /* first go through and calculate normals for all the polys */ - if (vnors == nullptr) { - vnors = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__); - free_vnors = true; - } - else { - memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts); - } - - MeshCalcNormalsData data; - data.mpolys = mpolys; - data.mloop = mloop; - data.mverts = mverts; - data.pnors = pnors; - data.vnors = vnors; - - /* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */ - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_and_accum_cb, &settings); - - /* Normalize and validate computed vertex normals (`vnors`). */ - BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); - - if (free_vnors) { - MEM_freeN(vnors); - } -} - void BKE_mesh_ensure_normals(Mesh *mesh) { if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { @@ -446,15 +489,25 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) } /* calculate poly/vert normals */ - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - poly_nors, - !do_vert_normals); + if (do_vert_normals) { + BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + poly_nors, + nullptr); + } + else { + BKE_mesh_calc_normals_poly(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + poly_nors); + } if (do_add_poly_nors_cddata) { CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly); @@ -472,15 +525,14 @@ void BKE_mesh_calc_normals(Mesh *mesh) #ifdef DEBUG_TIME TIMEIT_START_AVERAGED(BKE_mesh_calc_normals); #endif - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - nullptr, - false); + BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + nullptr, + nullptr); #ifdef DEBUG_TIME TIMEIT_END_AVERAGED(BKE_mesh_calc_normals); #endif @@ -2121,15 +2173,14 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool free_polynors = false; if (polynors == nullptr) { polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__); - BKE_mesh_calc_normals_poly(mesh->mvert, - nullptr, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - polynors, - false); + BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + polynors, + nullptr); free_polynors = true; } diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index c5e8858ea12..53a31cbbc7a 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1379,14 +1379,12 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } if (dirty_nors_dst || do_poly_nors_dst) { BKE_mesh_calc_normals_poly(verts_dst, - NULL, numverts_dst, loops_dst, - polys_dst, numloops_dst, + polys_dst, numpolys_dst, - poly_nors_dst, - true); + poly_nors_dst); } } if (need_lnors_dst) { @@ -2231,14 +2229,12 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, } if (dirty_nors_dst) { BKE_mesh_calc_normals_poly(verts_dst, - NULL, numverts_dst, loops_dst, - polys_dst, numloops_dst, + polys_dst, numpolys_dst, - poly_nors_dst, - true); + poly_nors_dst); } } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index b2379610f65..c075d2550cb 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -1007,15 +1007,8 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator if (me->flag & ME_AUTOSMOOTH) { float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__); - BKE_mesh_calc_normals_poly(me->mvert, - NULL, - me->totvert, - me->mloop, - me->mpoly, - me->totloop, - me->totpoly, - polynors, - true); + BKE_mesh_calc_normals_poly( + me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors); BKE_edges_sharp_from_angle_set(me->mvert, me->totvert, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index e7750f0a0d1..1dbdcf87d63 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -556,15 +556,13 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys); CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY); } - BKE_mesh_calc_normals_poly(mvert, - NULL, - num_verts, - mloop, - mpoly, - num_loops, - num_polys, - polynors, - (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) ? false : true); + if (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals_poly_and_vertex( + mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors, NULL); + } + else { + BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors); + } result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 64e1eb92fda..00fa6e24a64 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -259,14 +259,12 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex /* calculate only face normals */ poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); BKE_mesh_calc_normals_poly(orig_mvert, - NULL, (int)numVerts, orig_mloop, - orig_mpoly, (int)numLoops, + orig_mpoly, (int)numPolys, - poly_nors, - true); + poly_nors); } STACK_INIT(new_vert_arr, numVerts * 2); diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 18d308e5f02..5b4716a1a43 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -211,15 +211,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, /* Calculate only face normals. */ poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); - BKE_mesh_calc_normals_poly(orig_mvert, - NULL, - (int)numVerts, - orig_mloop, - orig_mpoly, - (int)numLoops, - (int)numPolys, - poly_nors, - true); + BKE_mesh_calc_normals_poly( + orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors); NewFaceRef *face_sides_arr = MEM_malloc_arrayN( numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify"); diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 3b147c69716..1ee64b935b7 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -615,8 +615,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY); } - BKE_mesh_calc_normals_poly( - mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false); + BKE_mesh_calc_normals_poly_and_vertex( + mvert, numVerts, mloop, numLoops, mpoly, numPolys, polynors, NULL); const float split_angle = mesh->smoothresh; short(*clnors)[2]; -- cgit v1.2.3 From ab344775c2c5aa6553981469a27062fd9b15dc87 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 13:53:27 +1000 Subject: Cleanup: code-comments Use capitalization, remove unnecessary ellipsis. --- source/blender/blenkernel/intern/mesh_normals.cc | 124 +++++++++++------------ 1 file changed, 60 insertions(+), 64 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index fe28f10d2db..a1c34be4a74 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -197,8 +197,8 @@ static void mesh_calc_normals_poly_and_vertex_accum_fn( const int i_end = mp->totloop - 1; - /* Polygon Normal and edge-vector */ - /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ + /* Polygon Normal and edge-vector. */ + /* Inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors. */ { zero_v3(pnor); /* Newell's Method */ @@ -209,12 +209,12 @@ static void mesh_calc_normals_poly_and_vertex_accum_fn( v_curr = v_next; } if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { - pnor[2] = 1.0f; /* other axes set to 0.0 */ + pnor[2] = 1.0f; /* Other axes set to zero. */ } } /* Accumulate angle weighted face normal into the vertex normal. */ - /* inline version of #accumulate_vertex_normals_poly_v3. */ + /* Inline version of #accumulate_vertex_normals_poly_v3. */ { float edvec_prev[3], edvec_next[3], edvec_end[3]; const float *v_curr = mverts[ml[i_end].v].co; @@ -254,7 +254,7 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn( float *no = data->vnors[vidx]; if (UNLIKELY(normalize_v3(no) == 0.0f)) { - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + /* Following Mesh convention; we use vertex coordinate itself for normal in this case. */ normalize_v3_v3(no, mv->co); } @@ -277,7 +277,7 @@ void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert, float(*vnors)[3] = r_vert_normals; bool free_vnors = false; - /* first go through and calculate normals for all the polys */ + /* First go through and calculate normals for all the polys. */ if (vnors == nullptr) { vnors = (float(*)[3])MEM_calloc_arrayN((size_t)mvert_len, sizeof(*vnors), __func__); free_vnors = true; @@ -375,7 +375,9 @@ void BKE_mesh_calc_normals_mapping(MVert *mverts, r_faceNors, false); } -/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */ +/** + * Extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals. + */ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, int numVerts, const MLoop *mloop, @@ -398,7 +400,7 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, return; } - /* if we are not calculating verts and no verts were passes then we have nothing to do */ + /* If we are not calculating verts and no verts were passes then we have nothing to do. */ if ((only_face_normals == true) && (r_polyNors == nullptr) && (r_faceNors == nullptr)) { CLOG_WARN(&LOG, "called with nothing to do"); return; @@ -411,13 +413,12 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, // if (!fnors) {fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); } if (only_face_normals == false) { - /* vertex normals are optional, they require some extra calculations, - * so make them optional */ + /* Vertex normals are optional, they require some extra calculations, so make them optional. */ BKE_mesh_calc_normals_poly_and_vertex( mverts, numVerts, mloop, numLoops, mpolys, numPolys, pnors, nullptr); } else { - /* only calc poly normals */ + /* Only calc poly normals. */ const MPoly *mp = mpolys; for (int i = 0; i < numPolys; i++, mp++) { BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); @@ -425,7 +426,7 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, } if (origIndexFace && - /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */ + /* `fnors == r_faceNors` */ /* NO NEED TO ALLOC YET */ fnors != nullptr && numFaces) { const MFace *mf = mfaces; @@ -434,8 +435,8 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, copy_v3_v3(fnors[i], pnors[*origIndexFace]); } else { - /* eek, we're not corresponding to polys */ - CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad."); + /* Yikes, we're not corresponding to polys. */ + CLOG_ERROR(&LOG, "tessellation face indices are incorrect. Normals may look bad."); } } } @@ -488,7 +489,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) (size_t)mesh->totpoly, sizeof(*poly_nors), __func__); } - /* calculate poly/vert normals */ + /* Calculate poly/vert normals. */ if (do_vert_normals) { BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, mesh->totvert, @@ -518,8 +519,10 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) } } -/* Note that this does not update the CD_NORMAL layer, - * but does update the normals in the CD_MVERT layer. */ +/** + * NOTE: this does not update the #CD_NORMAL layer, + * but does update the normals in the #CD_MVERT layer. + */ void BKE_mesh_calc_normals(Mesh *mesh) { #ifdef DEBUG_TIME @@ -575,7 +578,7 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts, mverts[vtri[2]].co); } - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + /* Following Mesh convention; we use vertex coordinate itself for normal in this case. */ for (int i = 0; i < numVerts; i++) { MVert *mv = &mverts[i]; float *no = tnorms[i]; @@ -715,11 +718,11 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, BLI_stack_discard(edge_vectors); nbr++; } - /* NOTE: In theory, this could be 'nbr > 2', - * but there is one case where we only have two edges for two loops: - * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). + /* NOTE: In theory, this could be `nbr > 2`, + * but there is one case where we only have two edges for two loops: + * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */ - BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */ + BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop. */ lnor_space->ref_alpha = alpha / (float)nbr; } else { @@ -791,7 +794,7 @@ MINLINE float unit_short_to_float(const short val) MINLINE short unit_float_to_short(const float val) { - /* Rounding... */ + /* Rounding. */ return (short)floorf(val * (float)SHRT_MAX + 0.5f); } @@ -1002,7 +1005,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, e2l[1] = INDEX_INVALID; /* We want to avoid tagging edges as sharp when it is already defined as such by - * other causes than angle threshold... */ + * other causes than angle threshold. */ if (do_sharp_edges_tag && is_angle_sharp) { BLI_BITMAP_SET(sharp_edges, ml_curr->e, true); } @@ -1016,7 +1019,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data, e2l[1] = INDEX_INVALID; /* We want to avoid tagging edges as sharp when it is already defined as such by - * other causes than angle threshold... */ + * other causes than angle threshold. */ if (do_sharp_edges_tag) { BLI_BITMAP_SET(sharp_edges, ml_curr->e, false); } @@ -1098,14 +1101,13 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, const MLoop *mlfan_next; const MPoly *mpfan_next; - /* Warning! This is rather complex! + /* WARNING: This is rather complex! * We have to find our next edge around the vertex (fan mode). * First we find the next loop, which is either previous or next to mlfan_curr_index, depending * whether both loops using current edge are in the same direction or not, and whether * mlfan_curr_index actually uses the vertex we are fanning around! * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one - * (i.e. not the future mlfan_curr)... - */ + * (i.e. not the future `mlfan_curr`). */ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0]; *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index]; @@ -1130,7 +1132,7 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops, *r_mlfan_vert_index = *r_mlfan_curr_index; } *r_mlfan_curr = &mloops[*r_mlfan_curr_index]; - /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */ + /* And now we are back in sync, mlfan_curr_index is the index of `mlfan_curr`! Pff! */ } static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data) @@ -1185,8 +1187,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS normalize_v3(vec_prev); BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, nullptr); - /* We know there is only one loop in this space, - * no need to create a linklist in this case... */ + /* We know there is only one loop in this space, no need to create a link-list in this case. */ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true); if (clnors_data) { @@ -1222,24 +1223,24 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli BLI_Stack *edge_vectors = data->edge_vectors; - /* Gah... We have to fan around current vertex, until we find the other non-smooth edge, + /* Sigh! we have to fan around current vertex, until we find the other non-smooth edge, * and accumulate face normals into the vertex! * Note in case this vertex has only one sharp edges, this is a waste because the normal is the * same as the vertex normal, but I do not see any easy way to detect that (would need to count * number of sharp edges per vertex, I doubt the additional memory usage would be worth it, - * especially as it should not be a common case in real-life meshes anyway). - */ + * especially as it should not be a common case in real-life meshes anyway). */ const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ const MVert *mv_pivot = &mverts[mv_pivot_index]; - /* ml_curr would be mlfan_prev if we needed that one. */ + /* `ml_curr` would be mlfan_prev if we needed that one. */ const MEdge *me_org = &medges[ml_curr->e]; const int *e2lfan_curr; float vec_curr[3], vec_prev[3], vec_org[3]; const MLoop *mlfan_curr; float lnor[3] = {0.0f, 0.0f, 0.0f}; - /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ + /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! + */ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; /* We validate clnors data on the fly - cheapest way to do! */ @@ -1283,7 +1284,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli /* Compute edge vectors. * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing * them twice (or more) here. However, time gained is not worth memory and time lost, - * given the fact that this code should not be called that much in real-life meshes... + * given the fact that this code should not be called that much in real-life meshes. */ { const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : @@ -1475,12 +1476,13 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ const int *e2lfan_curr; const MLoop *mlfan_curr; - /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ + /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! + */ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; e2lfan_curr = e2l_prev; if (IS_EDGE_SHARP(e2lfan_curr)) { - /* Sharp loop, so not a cyclic smooth fan... */ + /* Sharp loop, so not a cyclic smooth fan. */ return false; } @@ -1511,21 +1513,21 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops, e2lfan_curr = edge_to_loops[mlfan_curr->e]; if (IS_EDGE_SHARP(e2lfan_curr)) { - /* Sharp loop/edge, so not a cyclic smooth fan... */ + /* Sharp loop/edge, so not a cyclic smooth fan. */ return false; } - /* Smooth loop/edge... */ + /* Smooth loop/edge. */ if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) { if (mlfan_vert_index == ml_curr_index) { /* We walked around a whole cyclic smooth fan without finding any already-processed loop, - * means we can use initial ml_curr/ml_prev edge as start for this smooth fan. */ + * means we can use initial `ml_curr` / `ml_prev` edge as start for this smooth fan. */ return true; } - /* ... already checked in some previous looping, we can abort. */ + /* Already checked in some previous looping, we can abort. */ return false; } - /* ... we can skip it in future, and keep checking the smooth fan. */ + /* We can skip it in future, and keep checking the smooth fan. */ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index); } } @@ -1587,7 +1589,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common const int *e2l_prev = edge_to_loops[ml_prev->e]; #if 0 - printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...", + printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)", ml_curr_index, ml_curr->e, ml_curr->v, @@ -1691,7 +1693,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common } } - /* Last block of data... Since it is calloc'ed and we use first nullptr item as stopper, + /* Last block of data. Since it is calloc'ed and we use first nullptr item as stopper, * everything is fine. */ if (pool && data_idx) { BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr); @@ -1738,8 +1740,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, * since we may want to use lnors even when mesh's 'autosmooth' is disabled * (see e.g. mesh mapping code). * As usual, we could handle that on case-by-case basis, - * but simpler to keep it well confined here. - */ + * but simpler to keep it well confined here. */ int mp_index; for (mp_index = 0; mp_index < numPolys; mp_index++) { @@ -1822,7 +1823,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false); if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { - /* Not enough loops to be worth the whole threading overhead... */ + /* Not enough loops to be worth the whole threading overhead. */ loop_split_generator(nullptr, &common_data); } else { @@ -1877,13 +1878,12 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, short (*r_clnors_data)[2], const bool use_vertices) { - /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling + /* We *may* make that poor #BKE_mesh_normals_loop_split() even more complex by making it handling * that feature too, would probably be more efficient in absolute. * However, this function *is not* performance-critical, since it is mostly expected to be called - * by io addons when importing custom normals, and modifier + * by io add-ons when importing custom normals, and modifier * (and perhaps from some editing tools later?). - * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice! - */ + * So better to keep some simplicity here, and just call #BKE_mesh_normals_loop_split() twice! */ MLoopNorSpaceArray lnors_spacearr = {nullptr}; BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__); float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__); @@ -1935,15 +1935,13 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans * matching given custom lnors. * Note this code *will never* unsharp edges! And quite obviously, - * when we set custom normals per vertices, running this is absolutely useless. - */ + * when we set custom normals per vertices, running this is absolutely useless. */ if (!use_vertices) { for (int i = 0; i < numLoops; i++) { if (!lnors_spacearr.lspacearr[i]) { /* This should not happen in theory, but in some rare case (probably ugly geometry) * we can get some nullptr loopspacearr at this point. :/ - * Maybe we should set those loops' edges as sharp? - */ + * Maybe we should set those loops' edges as sharp? */ BLI_BITMAP_ENABLE(done_loops, i); if (G.debug & G_DEBUG) { printf("WARNING! Getting invalid nullptr loop space for loop %d!\n", i); @@ -1953,12 +1951,12 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, if (!BLI_BITMAP_TEST(done_loops, i)) { /* Notes: - * * In case of mono-loop smooth fan, we have nothing to do. - * * Loops in this linklist are ordered (in reversed order compared to how they were + * - In case of mono-loop smooth fan, we have nothing to do. + * - Loops in this linklist are ordered (in reversed order compared to how they were * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). * Which means if we find a mismatching clnor, * we know all remaining loops will have to be in a new, different smooth fan/lnor space. - * * In smooth fan case, we compare each clnor against a ref one, + * - In smooth fan case, we compare each clnor against a ref one, * to avoid small differences adding up into a real big one in the end! */ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { @@ -1983,8 +1981,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, /* Current normal differs too much from org one, we have to tag the edge between * previous loop's face and current's one as sharp. * We know those two loops do not point to the same edge, - * since we do not allow reversed winding in a same smooth fan. - */ + * since we do not allow reversed winding in a same smooth fan. */ const MPoly *mp = &mpolys[loop_to_poly[lidx]]; const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; @@ -2056,8 +2053,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts, if (BLI_BITMAP_TEST_BOOL(done_loops, i)) { /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can - * give rather huge differences in computed 2D factors). - */ + * give rather huge differences in computed 2D factors). */ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { BLI_assert(POINTER_AS_INT(loops) == i); -- cgit v1.2.3 From b51a473e294e83899a4c28a5659dab7ab55968d6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 14:37:30 +1000 Subject: Cleanup: remove use of BKE_mesh_calc_normals_mapping_simple Use BKE_mesh_calc_normals instead of BKE_mesh_calc_normals_mapping_simple for curve modifier calculation. This only made sense for derived-mesh which is no longer used. --- source/blender/blenkernel/intern/displist.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 99dc1db9d38..c97e07ad487 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -1003,7 +1003,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, modified = temp_mesh; BKE_mesh_vert_coords_apply(modified, vertCos); - BKE_mesh_calc_normals_mapping_simple(modified); + BKE_mesh_calc_normals(modified); MEM_freeN(vertCos); } -- cgit v1.2.3 From 92f4abc37f0febbce7bedfdc6284d282a26ca454 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 14:41:42 +1000 Subject: Cleanup: remove unused BKE_mesh_calc_normals_mapping functions This supported calculating normals for MPoly array which was copied to an MFace aligned array. Remove the functions entirely since MFace use is being phased out and these function isn't used anywhere. --- source/blender/blenkernel/BKE_mesh.h | 24 ---- source/blender/blenkernel/intern/mesh_normals.cc | 141 ----------------------- 2 files changed, 165 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 4eb3e6a3136..8000e57e08e 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -281,30 +281,6 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop, /* *** mesh_normals.cc *** */ void BKE_mesh_normals_tag_dirty(struct Mesh *mesh); -void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me); -void BKE_mesh_calc_normals_mapping(struct MVert *mverts, - int numVerts, - const struct MLoop *mloop, - const struct MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const struct MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3]); -void BKE_mesh_calc_normals_mapping_ex(struct MVert *mverts, - int numVerts, - const struct MLoop *mloop, - const struct MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const struct MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3], - const bool only_face_normals); void BKE_mesh_calc_normals_poly(const struct MVert *mvert, int mvert_len, const struct MLoop *mloop, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index a1c34be4a74..9a761c6fa11 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -27,8 +27,6 @@ #include -#include "CLG_log.h" - #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" @@ -59,8 +57,6 @@ # include "PIL_time_utildefines.h" #endif -static CLG_LogRef LOG = {"bke.mesh_normals"}; - /* -------------------------------------------------------------------- */ /** \name Private Utility Functions * \{ */ @@ -312,143 +308,6 @@ void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert, /** \name Mesh Normal Calculation * \{ */ -/** - * Call when there are no polygons. - */ -static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) -{ - for (int i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float no[3]; - - normalize_v3_v3(no, mv->co); - normal_float_to_short_v3(mv->no, no); - } -} - -/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(), - * and remove the function of the same name below, as that one doesn't seem to be - * called anywhere. */ -void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh) -{ - const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT); - - BKE_mesh_calc_normals_mapping_ex(mesh->mvert, - mesh->totvert, - mesh->mloop, - mesh->mpoly, - mesh->totloop, - mesh->totpoly, - nullptr, - mesh->mface, - mesh->totface, - nullptr, - nullptr, - only_face_normals); -} - -/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-nullptr - * and vertex normals are stored in actual mverts. - */ -void BKE_mesh_calc_normals_mapping(MVert *mverts, - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3]) -{ - BKE_mesh_calc_normals_mapping_ex(mverts, - numVerts, - mloop, - mpolys, - numLoops, - numPolys, - r_polyNors, - mfaces, - numFaces, - origIndexFace, - r_faceNors, - false); -} -/** - * Extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals. - */ -void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, - int numVerts, - const MLoop *mloop, - const MPoly *mpolys, - int numLoops, - int numPolys, - float (*r_polyNors)[3], - const MFace *mfaces, - int numFaces, - const int *origIndexFace, - float (*r_faceNors)[3], - const bool only_face_normals) -{ - float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors; - - if (numPolys == 0) { - if (only_face_normals == false) { - mesh_calc_normals_vert_fallback(mverts, numVerts); - } - return; - } - - /* If we are not calculating verts and no verts were passes then we have nothing to do. */ - if ((only_face_normals == true) && (r_polyNors == nullptr) && (r_faceNors == nullptr)) { - CLOG_WARN(&LOG, "called with nothing to do"); - return; - } - - if (!pnors) { - pnors = (float(*)[3])MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__); - } - /* NO NEED TO ALLOC YET */ - // if (!fnors) {fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); } - - if (only_face_normals == false) { - /* Vertex normals are optional, they require some extra calculations, so make them optional. */ - BKE_mesh_calc_normals_poly_and_vertex( - mverts, numVerts, mloop, numLoops, mpolys, numPolys, pnors, nullptr); - } - else { - /* Only calc poly normals. */ - const MPoly *mp = mpolys; - for (int i = 0; i < numPolys; i++, mp++) { - BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); - } - } - - if (origIndexFace && - /* `fnors == r_faceNors` */ /* NO NEED TO ALLOC YET */ - fnors != nullptr && - numFaces) { - const MFace *mf = mfaces; - for (int i = 0; i < numFaces; i++, mf++, origIndexFace++) { - if (*origIndexFace < numPolys) { - copy_v3_v3(fnors[i], pnors[*origIndexFace]); - } - else { - /* Yikes, we're not corresponding to polys. */ - CLOG_ERROR(&LOG, "tessellation face indices are incorrect. Normals may look bad."); - } - } - } - - if (pnors != r_polyNors) { - MEM_freeN(pnors); - } - // if (fnors != r_faceNors) { MEM_freeN(fnors); } /* NO NEED TO ALLOC YET */ - - fnors = pnors = nullptr; -} - void BKE_mesh_ensure_normals(Mesh *mesh) { if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { -- cgit v1.2.3 From 8fa05efe0a19126b44cc283232e05e0e53d6db84 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 15:10:27 +1000 Subject: Docs: note that normalize_v# functions zero out input containing nan --- source/blender/blenlib/intern/math_vector_inline.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index dddefd60b1b..ddfdaffb706 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -1145,6 +1145,9 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) return len_v3(d); } +/** + * \note any vectors containing `nan` will be zeroed out. + */ MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length) { float d = dot_v2v2(a, a); @@ -1154,6 +1157,7 @@ MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float u mul_v2_v2fl(r, a, unit_length / d); } else { + /* Either the vector is small or one of it's values contained `nan`. */ zero_v2(r); d = 0.0f; } @@ -1175,17 +1179,20 @@ MINLINE float normalize_v2_length(float n[2], const float unit_length) return normalize_v2_v2_length(n, n, unit_length); } +/** + * \note any vectors containing `nan` will be zeroed out. + */ MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length) { float d = dot_v3v3(a, a); - /* a larger value causes normalize errors in a - * scaled down models with camera extreme close */ + /* A larger value causes normalize errors in a scaled down models with camera extreme close. */ if (d > 1.0e-35f) { d = sqrtf(d); mul_v3_v3fl(r, a, unit_length / d); } else { + /* Either the vector is small or one of it's values contained `nan`. */ zero_v3(r); d = 0.0f; } -- cgit v1.2.3 From 41e650981861c2f18ab0548e18851d1d761066ff Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 15:36:49 +1000 Subject: Mesh: replace saacos with acosf for normal calculation The clamped version of acos isn't needed as degenerate (nan) coordinates result in zeroed vectors which don't need clamping. --- source/blender/blenkernel/intern/mesh_normals.cc | 14 +++++++++----- source/blender/blenlib/intern/math_geom.c | 12 ++++++++---- source/blender/bmesh/intern/bmesh_mesh_normals.c | 18 +++++++++++------- 3 files changed, 28 insertions(+), 16 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 9a761c6fa11..aae50fa165e 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -230,8 +230,10 @@ static void mesh_calc_normals_poly_and_vertex_accum_fn( copy_v3_v3(edvec_next, edvec_end); } - /* Calculate angle between the two poly edges incident on this vertex. */ - const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ + const float fac = acosf(-dot_v3v3(edvec_prev, edvec_next)); const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); @@ -1156,9 +1158,11 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); { - /* Code similar to accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. */ - const float fac = saacos(dot_v3v3(vec_curr, vec_prev)); + /* Code similar to #accumulate_vertex_normals_poly_v3. */ + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ + const float fac = acosf(dot_v3v3(vec_curr, vec_prev)); /* Accumulate */ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 8afb6b5a2be..43f2e08cf69 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -5307,7 +5307,10 @@ void accumulate_vertex_normals_tri_v3(float n1[3], for (i = 0; i < nverts; i++) { const float *cur_edge = vdiffs[i]; - const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ + const float fac = acosf(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ madd_v3_v3fl(vn[i], f_no, fac); @@ -5386,9 +5389,10 @@ void accumulate_vertex_normals_poly_v3(float **vertnos, for (i = 0; i < nverts; i++) { const float *cur_edge = vdiffs[i]; - /* calculate angle between the two poly edges incident on - * this vertex */ - const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ + const float fac = acosf(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ madd_v3_v3fl(vertnos[i], polyno, fac); diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index a5e41b74ee1..6a2cfdb056c 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -84,11 +84,13 @@ BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter, if ((l_iter->prev->e->v1 == l_iter->prev->v) ^ (l_iter->e->v1 == l_iter->v)) { dotprod = -dotprod; } - const float fac = saacos(-dotprod); - /* NAN detection, otherwise this is a degenerated case, ignore that vertex in this case. */ - if (fac == fac) { - madd_v3_v3fl(v_no, f_no, fac); - } + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ + const float fac = acosf(-dotprod); + /* NAN values should never happen. */ + BLI_assert(fac == fac); + madd_v3_v3fl(v_no, f_no, fac); } static void bm_vert_calc_normals_impl(BMVert *v) @@ -680,9 +682,11 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm, { /* Code similar to accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. */ + /* Calculate angle between the two poly edges incident on this vertex. + * NOTE: no need for #saacos here as the input has been sanitized, + * `nan` values in coordinates normalize to zero which works for `acosf`. */ const BMFace *f = lfan_pivot->f; - const float fac = saacos(dot_v3v3(vec_next, vec_curr)); + const float fac = acosf(dot_v3v3(vec_next, vec_curr)); const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; /* Accumulate */ madd_v3_v3fl(lnor, no, fac); -- cgit v1.2.3 From 3e775a4fc57cfd48954adcf284354312f34d5412 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 15:51:08 +1000 Subject: PyAPI: remove the .py extension requirement for startup registration This was left over from when these scripts were loaded as modules, where their names needed to be compatible with Pythons module naming. Version patch existing files so text with register enabled without a `.py` extension wont start executing on startup. Resolves T89532. --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_300.c | 36 +++++++++++++++-------- source/blender/python/intern/bpy_interface.c | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 5ef56fab9cb..4ed4225c836 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 17 +#define BLENDER_FILE_SUBVERSION 18 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 862ef99fca5..cac607ed152 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -22,6 +22,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -738,18 +739,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ - + if (!MAIN_VERSION_ATLEAST(bmain, 300, 18)) { if (!DNA_struct_elem_find( fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref")) { LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { @@ -775,5 +765,27 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Previously, only text ending with `.py` would run, apply this logic + * to existing files so text that happens to have the "Register" enabled + * doesn't suddenly start running code on startup that was previously ignored. */ + LISTBASE_FOREACH (Text *, text, &bmain->texts) { + if ((text->flags & TXT_ISSCRIPT) && !BLI_path_extension_check(text->id.name + 2, ".py")) { + text->flags &= ~TXT_ISSCRIPT; + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ } } diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 945933dd8b7..1a308414bc3 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -655,7 +655,7 @@ void BPY_modules_load_user(bContext *C) bpy_context_set(C, &gilstate); for (text = bmain->texts.first; text; text = text->id.next) { - if (text->flags & TXT_ISSCRIPT && BLI_path_extension_check(text->id.name + 2, ".py")) { + if (text->flags & TXT_ISSCRIPT) { if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) { if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) { G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL; -- cgit v1.2.3 From 160d57d33c7f100556b6c69b524783a3ac52b53b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 16:01:45 +1000 Subject: Docs: tooltip update missing from 3e775a4fc57cfd48954adcf284354312f34d5412 --- source/blender/makesrna/intern/rna_text.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index 1351c027004..52f762e5494 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -240,8 +240,7 @@ static void rna_def_text(BlenderRNA *brna) prop = RNA_def_property(srna, "use_module", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", TXT_ISSCRIPT); - RNA_def_property_ui_text( - prop, "Register", "Run this text as a script on loading, Text name must end with \".py\""); + RNA_def_property_ui_text(prop, "Register", "Run this text as a Python script on loading"); prop = RNA_def_property(srna, "indentation", PROP_ENUM, PROP_NONE); /* as an enum */ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); -- cgit v1.2.3 From 7b5acc80091d8d92869d83f1308f5af24b45ce9a Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 13 Aug 2021 08:34:10 +0200 Subject: Cleanup: remove unused draw_gpencil_channel. Code is integrated with draw_scene_channel since 2.80. --- source/blender/editors/animation/keyframes_draw.c | 14 -------------- source/blender/editors/include/ED_keyframes_draw.h | 7 ------- 2 files changed, 21 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index d25f81005c5..5407e04af12 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -685,20 +685,6 @@ void draw_action_channel(AnimKeylistDrawList *draw_list, draw_elem->channel_locked = locked; } -void draw_gpencil_channel( - View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag) -{ - struct AnimKeylist *keylist = ED_keylist_create(); - - saction_flag &= ~SACTION_SHOW_EXTREMES; - - gpencil_to_keylist(ads, gpd, keylist, false); - - draw_keylist(v2d, keylist, ypos, yscale_fac, false, saction_flag); - - ED_keylist_free(keylist); -} - void draw_gpl_channel(AnimKeylistDrawList *draw_list, bDopeSheet *ads, bGPDlayer *gpl, diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index c9bbf58ff7a..50823045936 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -102,13 +102,6 @@ void draw_summary_channel(struct AnimKeylistDrawList *draw_list, float ypos, float yscale_fac, int saction_flag); -/* Grease Pencil datablock summary */ -void draw_gpencil_channel(struct View2D *v2d, - struct bDopeSheet *ads, - struct bGPdata *gpd, - float ypos, - float yscale_fac, - int saction_flag); /* Grease Pencil Layer */ void draw_gpl_channel(struct AnimKeylistDrawList *draw_list, struct bDopeSheet *ads, -- cgit v1.2.3 From 5f6033e0919a9a6bfd00a8a977d28fa60fe7f079 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 13 Aug 2021 09:37:38 +0200 Subject: Keyframe: Reduce GPU context switches. This change reduces the GPU context switches when drawing keyframes. In the previous situation the keyframe blocks and keyframe keys were drawn per channel. With this patch first all the keyframe blocks are drawn for all channels and after that the keyframe keys are collected for all channels and send to the GPU in a single draw call. --- source/blender/editors/animation/keyframes_draw.c | 216 +++++++++++---------- source/blender/editors/include/ED_keyframes_draw.h | 14 +- source/blender/editors/interface/interface_icons.c | 17 +- source/blender/editors/space_nla/nla_draw.c | 19 +- 4 files changed, 143 insertions(+), 123 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 5407e04af12..61918871b90 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -57,11 +57,7 @@ void draw_keyframe_shape(float x, short key_type, short mode, float alpha, - uint pos_id, - uint size_id, - uint color_id, - uint outline_color_id, - uint flags_id, + const KeyframeShaderBindings *sh_bindings, short handle_type, short extreme_type) { @@ -178,11 +174,11 @@ void draw_keyframe_shape(float x, } } - immAttr1f(size_id, size); - immAttr4ubv(color_id, fill_col); - immAttr4ubv(outline_color_id, outline_col); - immAttr1u(flags_id, flags); - immVertex2f(pos_id, x, y); + immAttr1f(sh_bindings->size_id, size); + immAttr4ubv(sh_bindings->color_id, fill_col); + immAttr4ubv(sh_bindings->outline_color_id, outline_col); + immAttr1u(sh_bindings->flags_id, flags); + immVertex2f(sh_bindings->pos_id, x, y); } /* Common attributes shared between the draw calls. */ @@ -363,98 +359,36 @@ static bool draw_keylist_is_visible_key(const View2D *v2d, const ActKeyColumn *a return IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax); } -static int draw_keylist_visible_key_len(View2D *v2d, const ListBase * /*ActKeyColumn*/ keys) -{ - /* count keys */ - uint len = 0; - - LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { - /* Optimization: if keyframe doesn't appear within 5 units (screenspace) - * in visible area, don't draw. - * This might give some improvements, - * since we current have to flip between view/region matrices. - */ - if (draw_keylist_is_visible_key(v2d, ak)) { - len++; - } - } - return len; -} - static void draw_keylist_keys(const DrawKeylistUIData *ctx, View2D *v2d, + const KeyframeShaderBindings *sh_bindings, const ListBase * /*ActKeyColumn*/ keys, float ypos, eSAction_Flag saction_flag) { - GPU_blend(GPU_BLEND_ALPHA); - const int key_len = draw_keylist_visible_key_len(v2d, keys); - if (key_len > 0) { - /* draw keys */ - GPUVertFormat *format = immVertexFormat(); - uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color_id = GPU_vertformat_attr_add( - format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint outline_color_id = GPU_vertformat_attr_add( - format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); - - GPU_program_point_size(true); - immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); - immUniform1f("outline_scale", 1.0f); - immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1); - immBegin(GPU_PRIM_POINTS, key_len); - - short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE; - - LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { - if (draw_keylist_is_visible_key(v2d, ak)) { - if (ctx->show_ipo) { - handle_type = ak->handle_type; - } - if (saction_flag & SACTION_SHOW_EXTREMES) { - extreme_type = ak->extreme_type; - } - - draw_keyframe_shape(ak->cfra, - ypos, - ctx->icon_sz, - (ak->sel & SELECT), - ak->key_type, - KEYFRAME_SHAPE_BOTH, - ctx->alpha, - pos_id, - size_id, - color_id, - outline_color_id, - flags_id, - handle_type, - extreme_type); + short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE; + + LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { + if (draw_keylist_is_visible_key(v2d, ak)) { + if (ctx->show_ipo) { + handle_type = ak->handle_type; + } + if (saction_flag & SACTION_SHOW_EXTREMES) { + extreme_type = ak->extreme_type; } - } - immEnd(); - GPU_program_point_size(false); - immUnbindProgram(); + draw_keyframe_shape(ak->cfra, + ypos, + ctx->icon_sz, + (ak->sel & SELECT), + ak->key_type, + KEYFRAME_SHAPE_BOTH, + ctx->alpha, + sh_bindings, + handle_type, + extreme_type); + } } - - GPU_blend(GPU_BLEND_NONE); -} - -static void draw_keylist(View2D *v2d, - const struct AnimKeylist *keylist, - float ypos, - float yscale_fac, - bool channelLocked, - eSAction_Flag saction_flag) -{ - DrawKeylistUIData ctx; - draw_keylist_ui_data_init(&ctx, v2d, yscale_fac, channelLocked, saction_flag); - - const ListBase *columns = ED_keylist_listbase(keylist); - draw_keylist_blocks(&ctx, columns, ypos); - draw_keylist_keys(&ctx, v2d, columns, ypos, saction_flag); } /* *************************** Drawing Stack *************************** */ @@ -530,10 +464,23 @@ static void ED_keylist_draw_list_elem_build_keylist(AnimKeylistDrawListElem *ele } } -static void ED_keylist_draw_list_elem_draw(AnimKeylistDrawListElem *elem, View2D *v2d) +static void ED_keylist_draw_list_elem_draw_blocks(AnimKeylistDrawListElem *elem, View2D *v2d) +{ + DrawKeylistUIData ctx; + draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag); + + const ListBase *keys = ED_keylist_listbase(elem->keylist); + draw_keylist_blocks(&ctx, keys, elem->ypos); +} + +static void ED_keylist_draw_list_elem_draw_keys(AnimKeylistDrawListElem *elem, + View2D *v2d, + const KeyframeShaderBindings *sh_bindings) { - draw_keylist( - v2d, elem->keylist, elem->ypos, elem->yscale_fac, elem->channel_locked, elem->saction_flag); + DrawKeylistUIData ctx; + draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag); + const ListBase *keys = ED_keylist_listbase(elem->keylist); + draw_keylist_keys(&ctx, v2d, sh_bindings, keys, elem->ypos, elem->saction_flag); } typedef struct AnimKeylistDrawList { @@ -552,13 +499,86 @@ static void ED_keylist_draw_list_build_keylists(AnimKeylistDrawList *draw_list) } } -static void ED_keylist_draw_list_draw(AnimKeylistDrawList *draw_list, View2D *v2d) +static void ED_keylist_draw_list_draw_blocks(AnimKeylistDrawList *draw_list, View2D *v2d) { LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { - ED_keylist_draw_list_elem_draw(elem, v2d); + ED_keylist_draw_list_elem_draw_blocks(elem, v2d); } } +static int ED_keylist_draw_keylist_visible_key_len(const View2D *v2d, + const ListBase * /*ActKeyColumn*/ keys) +{ + /* count keys */ + uint len = 0; + + LISTBASE_FOREACH (ActKeyColumn *, ak, keys) { + /* Optimization: if keyframe doesn't appear within 5 units (screenspace) + * in visible area, don't draw. + * This might give some improvements, + * since we current have to flip between view/region matrices. + */ + if (draw_keylist_is_visible_key(v2d, ak)) { + len++; + } + } + return len; +} + +static int ED_keylist_draw_list_visible_key_len(const AnimKeylistDrawList *draw_list, + const View2D *v2d) +{ + uint len = 0; + LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { + const ListBase *keys = ED_keylist_listbase(elem->keylist); + len += ED_keylist_draw_keylist_visible_key_len(v2d, keys); + } + return len; +} + +static void ED_keylist_draw_list_draw_keys(AnimKeylistDrawList *draw_list, View2D *v2d) +{ + const int visible_key_len = ED_keylist_draw_list_visible_key_len(draw_list, v2d); + if (visible_key_len == 0) { + return; + } + + GPU_blend(GPU_BLEND_ALPHA); + + GPUVertFormat *format = immVertexFormat(); + KeyframeShaderBindings sh_bindings; + + sh_bindings.pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + sh_bindings.size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + sh_bindings.color_id = GPU_vertformat_attr_add( + format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + sh_bindings.outline_color_id = GPU_vertformat_attr_add( + format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + sh_bindings.flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); + + GPU_program_point_size(true); + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + immUniform1f("outline_scale", 1.0f); + immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1); + immBegin(GPU_PRIM_POINTS, visible_key_len); + + LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) { + ED_keylist_draw_list_elem_draw_keys(elem, v2d, &sh_bindings); + } + + immEnd(); + GPU_program_point_size(false); + immUnbindProgram(); + + GPU_blend(GPU_BLEND_NONE); +} + +static void ED_keylist_draw_list_draw(AnimKeylistDrawList *draw_list, View2D *v2d) +{ + ED_keylist_draw_list_draw_blocks(draw_list, v2d); + ED_keylist_draw_list_draw_keys(draw_list, v2d); +} + void ED_keylist_draw_list_flush(AnimKeylistDrawList *draw_list, View2D *v2d) { ED_keylist_draw_list_build_keylists(draw_list); diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 50823045936..61e37f20b1b 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -43,6 +43,14 @@ struct bGPDlayer; /* draw simple diamond-shape keyframe */ /* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND, * immBegin(GPU_PRIM_POINTS, n), then call this n times */ +typedef struct KeyframeShaderBindings { + uint pos_id; + uint size_id; + uint color_id; + uint outline_color_id; + uint flags_id; +} KeyframeShaderBindings; + void draw_keyframe_shape(float x, float y, float size, @@ -50,11 +58,7 @@ void draw_keyframe_shape(float x, short key_type, short mode, float alpha, - unsigned int pos_id, - unsigned int size_id, - unsigned int color_id, - unsigned int outline_color_id, - unsigned int flags_id, + const KeyframeShaderBindings *sh_bindings, short handle_type, short extreme_type); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 2d59bfb92c8..f739830cfdb 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -299,13 +299,14 @@ static void vicon_keytype_draw_wrapper( const float yco = y + h / 2 + 0.5f; GPUVertFormat *format = immVertexFormat(); - const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - const uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color_id = GPU_vertformat_attr_add( + KeyframeShaderBindings sh_bindings; + sh_bindings.pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + sh_bindings.size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + sh_bindings.color_id = GPU_vertformat_attr_add( format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint outline_color_id = GPU_vertformat_attr_add( + sh_bindings.outline_color_id = GPU_vertformat_attr_add( format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - const uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); + sh_bindings.flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); GPU_program_point_size(true); immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); @@ -326,11 +327,7 @@ static void vicon_keytype_draw_wrapper( key_type, KEYFRAME_SHAPE_BOTH, alpha, - pos_id, - size_id, - color_id, - outline_color_id, - flags_id, + &sh_bindings, handle_type, KEYFRAME_EXTREME_NONE); diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 2bf4c7d4344..c1b308d213f 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -140,13 +140,16 @@ static void nla_action_draw_keyframes( if (key_len > 0) { format = immVertexFormat(); - pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color_id = GPU_vertformat_attr_add( + KeyframeShaderBindings sh_bindings; + sh_bindings.pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + sh_bindings.size_id = GPU_vertformat_attr_add( + format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + sh_bindings.color_id = GPU_vertformat_attr_add( format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint outline_color_id = GPU_vertformat_attr_add( + sh_bindings.outline_color_id = GPU_vertformat_attr_add( format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); + sh_bindings.flags_id = GPU_vertformat_attr_add( + format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); GPU_program_point_size(true); immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); @@ -165,11 +168,7 @@ static void nla_action_draw_keyframes( ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f, - pos_id, - size_id, - color_id, - outline_color_id, - flags_id, + &sh_bindings, KEYFRAME_HANDLE_NONE, KEYFRAME_EXTREME_NONE); } -- cgit v1.2.3 From 0ae23636e7e337b70ade5b172af291ac46a517ff Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 21 Apr 2021 17:26:18 +0200 Subject: Fix missing animation UI update in the Properties Editor Animation indicators as well as decorators for properties were not updating correctly in the following cases: - NLA pushdown (this was reported in T87681) - NLA enter/exit tweakmode - Outliner unlinking/setting action These actions all send a ND_NLA_ACTCHANGE notifier which the Properties Editor was not listening to [which is now added]. part of T87681. Maniphest Tasks: T87681 Differential Revision: https://developer.blender.org/D11040 --- source/blender/editors/space_buttons/space_buttons.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 57a7fe894b0..b04291b7ab4 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -811,6 +811,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params) break; case NC_ANIMATION: switch (wmn->data) { + case ND_NLA_ACTCHANGE: + ED_area_tag_redraw(area); + break; case ND_KEYFRAME: if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) { ED_area_tag_redraw(area); -- cgit v1.2.3 From 00f264ea42fb657cd4c62be54ae43459f480a6d8 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Fri, 13 Aug 2021 10:52:53 +0200 Subject: Cleanup: correct comment exiting NLA tweakmode Comment was pasted from entering tweakmode. --- source/blender/editors/space_nla/nla_edit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 56efcd8571f..c75b874833a 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -241,9 +241,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo) ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); - /* if we managed to enter tweak-mode on at least one AnimData block, - * set the flag for this in the active scene and send notifiers - */ + /* Clear the tweak-mode flag in the active scene and send notifiers. */ if (ac->scene) { /* clear editing flag */ ac->scene->flag &= ~SCE_NLA_EDIT_ON; -- cgit v1.2.3 From fd29a161cc892730859f6b28a026460f9dd4a1c5 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Thu, 22 Apr 2021 15:50:29 +0200 Subject: Fix Action Editor unlink button when in tweak mode When in NLA tweak mode, the action unlink button in the Dopesheet / Action Editor should be a mere shortcut to exiting tweak mode [nothing else]. Instead, it was also clearing the action fully, not returning to the previous edited action before going into tweak mode. Now dont "flush" by clearing the action, instead exit tweakmode, clear the scenes SCE_NLA_EDIT_ON flag (if this isnt done some NLA operators like pushdown were not immediately available because their poll checked this flag) and send appropriate notifier to have everything update nicely. Part of T87681 (Bug 4/5/6). Maniphest Tasks: T87681 Differential Revision: https://developer.blender.org/D11052 --- source/blender/editors/space_action/action_data.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index d69c7ab8d48..717d87c4972 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -599,16 +599,13 @@ void ED_animedit_unlink_action( id_fake_user_clear(&act->id); } - /* If in Tweak Mode, don't unlink. Instead, this - * becomes a shortcut to exit Tweak Mode instead - */ + /* If in Tweak Mode, don't unlink. Instead, this becomes a shortcut to exit Tweak Mode. */ if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { - /* Exit Tweak Mode */ BKE_nla_tweakmode_exit(adt); - /* Flush this to the Action Editor (if that's where this change was initiated) */ - if (area->spacetype == SPACE_ACTION) { - actedit_change_action(C, NULL); + Scene *scene = CTX_data_scene(C); + if (scene != NULL) { + scene->flag &= ~SCE_NLA_EDIT_ON; } } else { @@ -660,6 +657,9 @@ static int action_unlink_exec(bContext *C, wmOperator *op) ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete); } + /* Unlink is also abused to exit NLA tweak mode. */ + WM_main_add_notifier(NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + return OPERATOR_FINISHED; } -- cgit v1.2.3 From 4cadccebfacfa8533ba06403960e8b1218da61f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 13 Aug 2021 19:38:19 +1000 Subject: Revert "Mesh: replace saacos with acosf for normal calculation" This reverts commit 41e650981861c2f18ab0548e18851d1d761066ff. This broke "CubeMaskFirst" test. Any value even slightly outside the [-1.0..1.0] range caused the result to be nan, which can happen when calculating the dot-product between two unit length vectors. --- source/blender/blenkernel/intern/mesh_normals.cc | 14 +++++--------- source/blender/blenlib/intern/math_geom.c | 12 ++++-------- source/blender/bmesh/intern/bmesh_mesh_normals.c | 18 +++++++----------- 3 files changed, 16 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index aae50fa165e..9a761c6fa11 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -230,10 +230,8 @@ static void mesh_calc_normals_poly_and_vertex_accum_fn( copy_v3_v3(edvec_next, edvec_end); } - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ - const float fac = acosf(-dot_v3v3(edvec_prev, edvec_next)); + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next)); const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac}; add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add); @@ -1158,11 +1156,9 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); { - /* Code similar to #accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ - const float fac = acosf(dot_v3v3(vec_curr, vec_prev)); + /* Code similar to accumulate_vertex_normals_poly_v3. */ + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(dot_v3v3(vec_curr, vec_prev)); /* Accumulate */ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 43f2e08cf69..8afb6b5a2be 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -5307,10 +5307,7 @@ void accumulate_vertex_normals_tri_v3(float n1[3], for (i = 0; i < nverts; i++) { const float *cur_edge = vdiffs[i]; - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ - const float fac = acosf(-dot_v3v3(cur_edge, prev_edge)); + const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ madd_v3_v3fl(vn[i], f_no, fac); @@ -5389,10 +5386,9 @@ void accumulate_vertex_normals_poly_v3(float **vertnos, for (i = 0; i < nverts; i++) { const float *cur_edge = vdiffs[i]; - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ - const float fac = acosf(-dot_v3v3(cur_edge, prev_edge)); + /* calculate angle between the two poly edges incident on + * this vertex */ + const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ madd_v3_v3fl(vertnos[i], polyno, fac); diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index 6a2cfdb056c..a5e41b74ee1 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -84,13 +84,11 @@ BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter, if ((l_iter->prev->e->v1 == l_iter->prev->v) ^ (l_iter->e->v1 == l_iter->v)) { dotprod = -dotprod; } - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ - const float fac = acosf(-dotprod); - /* NAN values should never happen. */ - BLI_assert(fac == fac); - madd_v3_v3fl(v_no, f_no, fac); + const float fac = saacos(-dotprod); + /* NAN detection, otherwise this is a degenerated case, ignore that vertex in this case. */ + if (fac == fac) { + madd_v3_v3fl(v_no, f_no, fac); + } } static void bm_vert_calc_normals_impl(BMVert *v) @@ -682,11 +680,9 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm, { /* Code similar to accumulate_vertex_normals_poly_v3. */ - /* Calculate angle between the two poly edges incident on this vertex. - * NOTE: no need for #saacos here as the input has been sanitized, - * `nan` values in coordinates normalize to zero which works for `acosf`. */ + /* Calculate angle between the two poly edges incident on this vertex. */ const BMFace *f = lfan_pivot->f; - const float fac = acosf(dot_v3v3(vec_next, vec_curr)); + const float fac = saacos(dot_v3v3(vec_next, vec_curr)); const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no; /* Accumulate */ madd_v3_v3fl(lnor, no, fac); -- cgit v1.2.3 From 0b3c7544b532d99d80a25f3cb1f63f14480b46c8 Mon Sep 17 00:00:00 2001 From: "Matteo F. Vescovi" Date: Fri, 13 Aug 2021 14:33:37 +0200 Subject: Fix FTBFS on mips64el architecture While trying to get Blender 2.93.x LTS to build fine on all release architectures in Debian, I noticed that the misleading use of "mips" as integer variable caused problems when compiling on mips64el. The patch should fix the issue. Reviewed By: fclem Differential Revision: https://developer.blender.org/D12194 --- source/blender/draw/intern/draw_manager_texture.c | 24 +++++++++++------------ source/blender/gpu/GPU_texture.h | 14 ++++++------- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 73afdd6e1e3..99e8ba968a2 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -83,8 +83,8 @@ GPUTexture *DRW_texture_create_1d(int w, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_1d(__func__, w, mips, format, fpixels); + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + GPUTexture *tex = GPU_texture_create_1d(__func__, w, mip_len, format, fpixels); drw_texture_set_parameters(tex, flags); return tex; @@ -93,8 +93,8 @@ GPUTexture *DRW_texture_create_1d(int w, GPUTexture *DRW_texture_create_2d( int w, int h, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_2d(__func__, w, h, mips, format, fpixels); + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + GPUTexture *tex = GPU_texture_create_2d(__func__, w, h, mip_len, format, fpixels); drw_texture_set_parameters(tex, flags); return tex; @@ -103,8 +103,8 @@ GPUTexture *DRW_texture_create_2d( GPUTexture *DRW_texture_create_2d_array( int w, int h, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_2d_array(__func__, w, h, d, mips, format, fpixels); + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + GPUTexture *tex = GPU_texture_create_2d_array(__func__, w, h, d, mip_len, format, fpixels); drw_texture_set_parameters(tex, flags); return tex; @@ -113,9 +113,9 @@ GPUTexture *DRW_texture_create_2d_array( GPUTexture *DRW_texture_create_3d( int w, int h, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; GPUTexture *tex = GPU_texture_create_3d( - __func__, w, h, d, mips, format, GPU_DATA_FLOAT, fpixels); + __func__, w, h, d, mip_len, format, GPU_DATA_FLOAT, fpixels); drw_texture_set_parameters(tex, flags); return tex; @@ -126,8 +126,8 @@ GPUTexture *DRW_texture_create_cube(int w, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_cube(__func__, w, mips, format, fpixels); + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + GPUTexture *tex = GPU_texture_create_cube(__func__, w, mip_len, format, fpixels); drw_texture_set_parameters(tex, flags); return tex; } @@ -135,8 +135,8 @@ GPUTexture *DRW_texture_create_cube(int w, GPUTexture *DRW_texture_create_cube_array( int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) { - int mips = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; - GPUTexture *tex = GPU_texture_create_cube_array(__func__, w, d, mips, format, fpixels); + int mip_len = (flags & DRW_TEX_MIPMAP) ? 9999 : 1; + GPUTexture *tex = GPU_texture_create_cube_array(__func__, w, d, mip_len, format, fpixels); drw_texture_set_parameters(tex, flags); return tex; } diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index f980c8fdcd7..ee4d08d4059 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -187,25 +187,25 @@ unsigned int GPU_texture_memory_usage_get(void); * \a mips is the number of mip level to allocate. It must be >= 1. */ GPUTexture *GPU_texture_create_1d( - const char *name, int w, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_1d_array( - const char *name, int w, int h, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_2d( - const char *name, int w, int h, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_2d_array( - const char *name, int w, int h, int d, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int h, int d, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_3d(const char *name, int w, int h, int d, - int mips, + int mip_len, eGPUTextureFormat texture_format, eGPUDataFormat data_format, const void *data); GPUTexture *GPU_texture_create_cube( - const char *name, int w, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_cube_array( - const char *name, int w, int d, int mips, eGPUTextureFormat format, const float *data); + const char *name, int w, int d, int mip_len, eGPUTextureFormat format, const float *data); /* Special textures. */ GPUTexture *GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert); -- cgit v1.2.3 From 77744b581d082a692b35345bab57128c6915bc6d Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 11 Aug 2021 13:53:19 +0200 Subject: Fix T90595: some VSE strip properties do not identify strip name in anim channel names Working with multiple strips keyframes was unneccessarily difficult in Animation Editors (since some anim channels could not be distinguished). Namely `Crop` and `Transform` are nested structs (nested under `Sequence`), so these were just displaying the raw struct name. Also strip modifiers did not have their strip name in their channel names. Now include the strip name for these. before {F10277439} after {F10277441} Maniphest Tasks: T90595 Differential Revision: https://developer.blender.org/D12193 --- source/blender/editors/animation/anim_ipo_utils.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 5992545bdbe..eda87cf1897 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -134,6 +134,28 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) else { structname = RNA_struct_ui_name(ptr.type); } + + /* For the VSE, a strip's 'Transform' or 'Crop' is a nested (under Sequence) struct, but + * displaying the struct name alone is no meaningful information (and also cannot be + * filtered well), same for modifiers. So display strip name alongside as well. */ + if (GS(ptr.owner_id->name) == ID_SCE) { + if (BLI_str_startswith(fcu->rna_path, "sequence_editor.sequences_all[\"")) { + if (strstr(fcu->rna_path, ".transform.") || strstr(fcu->rna_path, ".crop.") || + strstr(fcu->rna_path, ".modifiers[")) { + char *stripname = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); + const char *structname_all = BLI_sprintfN( + "%s : %s", stripname ? stripname : "", structname); + if (free_structname) { + MEM_freeN((void *)structname); + } + if (stripname) { + MEM_freeN(stripname); + } + structname = structname_all; + free_structname = 1; + } + } + } } /* Property Name is straightforward */ -- cgit v1.2.3 From 7772880d696c306fa41a27af65f7a21a9168c616 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 13 Aug 2021 12:40:56 +0200 Subject: ViewLayer resync: Add sanity checks for objects/bases mappings. Add a debug-only check regarding consistency of the cache (mapping from objects to their bases) for a given ViewLayer. Issues can happen otherwise when some code does remapping of objects, and forgets to call `BKE_main_collection_sync_remap()` (which clears those caches) instead of `BKE_main_collection_sync()`. --- source/blender/blenkernel/intern/layer.c | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index e7d83c668c8..b489675cd74 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -1174,6 +1174,52 @@ static void layer_collection_sync(ViewLayer *view_layer, parent_local_collections_bits); } +#ifndef NDEBUG +static bool view_layer_objects_base_cache_validate(ViewLayer *view_layer, LayerCollection *layer) +{ + bool is_valid = true; + + if (layer == NULL) { + layer = view_layer->layer_collections.first; + } + + /* Only check for a collection's objects if its layer is not excluded. */ + if ((layer->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + LISTBASE_FOREACH (CollectionObject *, cob, &layer->collection->gobject) { + if (cob->ob == NULL) { + continue; + } + if (BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob) == NULL) { + CLOG_FATAL( + &LOG, + "Object '%s' from collection '%s' has no entry in view layer's object bases cache", + cob->ob->id.name + 2, + layer->collection->id.name + 2); + is_valid = false; + break; + } + } + } + + if (is_valid) { + LISTBASE_FOREACH (LayerCollection *, layer_child, &layer->layer_collections) { + if (!view_layer_objects_base_cache_validate(view_layer, layer_child)) { + is_valid = false; + break; + } + } + } + + return is_valid; +} +#else +static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer), + LayerCollection *UNUSED(layer)) +{ + return true; +} +#endif + /** * Update view layer collection tree from collections used in the scene. * This is used when collections are removed or added, both while editing @@ -1240,6 +1286,12 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) } if (base->object) { + /* Those asserts are commented, since they are too expensive to perform even in debug, as + * this layer resync function currently gets called way too often. */ +#if 0 + BLI_assert(BLI_findindex(&new_object_bases, base) == -1); + BLI_assert(BLI_findptr(&new_object_bases, base->object, offsetof(Base, object)) == NULL); +#endif BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); } } @@ -1247,6 +1299,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) BLI_freelistN(&view_layer->object_bases); view_layer->object_bases = new_object_bases; + view_layer_objects_base_cache_validate(view_layer, NULL); + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { BKE_base_eval_flags(base); } -- cgit v1.2.3 From bb0e29c922df43e13cfe5d18928c6ae2b942a945 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 13 Aug 2021 16:26:58 +0200 Subject: Blendloader: Option to reports to skip list of recursively liboverride-resynced libs. This extra info is not always needed/convinient to use, and requires special attention to free the list, so allow not generating it. --- source/blender/blenkernel/intern/lib_override.c | 2 +- source/blender/blenloader/BLO_readfile.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index bebc49e090d..8083585b594 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1631,7 +1631,7 @@ static void lib_override_library_main_resync_on_library_indirect_level( CLOG_INFO(&LOG, 2, "\tSuccess: %d", success); if (success) { reports->count.resynced_lib_overrides++; - if (library_indirect_level > 0 && + if (library_indirect_level > 0 && reports->do_resynced_lib_overrides_libraries_list && BLI_linklist_index(reports->resynced_lib_overrides_libraries, library) < 0) { BLI_linklist_prepend(&reports->resynced_lib_overrides_libraries, library); reports->resynced_lib_overrides_libraries_count++; diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index c3a33115613..dbdb181281a 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -118,6 +118,7 @@ typedef struct BlendFileReadReport { /* Number of libraries which had overrides that needed to be resynced, and a single linked list * of those. */ int resynced_lib_overrides_libraries_count; + bool do_resynced_lib_overrides_libraries_list; struct LinkNode *resynced_lib_overrides_libraries; } BlendFileReadReport; -- cgit v1.2.3 From 5225e459da07b10b5d1a77f74fed2d3df1fee594 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 13 Aug 2021 16:34:06 +0200 Subject: Fix T86883: Add/fix suport of liboverrides in relocate/reload library case. There was already some code for that, but it was broken, and proper resync was completely missing. There might still be more resync needed in library linking operators though. --- .../blender/windowmanager/intern/wm_files_link.c | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 7c3fce7fcb2..cdcb6c5163f 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -831,7 +831,7 @@ static void lib_relocate_do_remap(Main *bmain, } } -static void lib_relocate_do(Main *bmain, +static void lib_relocate_do(bContext *C, Library *library, WMLinkAppendData *lapp_data, ReportList *reports, @@ -843,6 +843,10 @@ static void lib_relocate_do(Main *bmain, LinkNode *itemlink; int item_idx; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + /* Remove all IDs to be reloaded from Main. */ lba_idx = set_listbasepointers(bmain, lbarray); while (lba_idx--) { @@ -990,21 +994,31 @@ static void lib_relocate_do(Main *bmain, } } - /* Update overrides of reloaded linked data-blocks. - * Note that this will not necessarily fully update the override, it might need to be manually - * 're-generated' depending on changes in linked data. */ + /* Update overrides of reloaded linked data-blocks. */ ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || (id->tag & LIB_TAG_PRE_EXISTING) == 0) { continue; } - if (id->override_library->reference->lib == library) { + if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { BKE_lib_override_library_update(bmain, id); } } FOREACH_MAIN_ID_END; + /* Resync overrides if needed. */ + if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { + BKE_lib_override_library_main_resync(bmain, + scene, + view_layer, + &(struct BlendFileReadReport){ + .reports = reports, + }); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); + } + BKE_main_collection_sync(bmain); BKE_main_lib_objects_recalc_all(bmain); @@ -1039,7 +1053,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) wm_link_append_data_library_add(lapp_data, lib->filepath_abs); - lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true); + lib_relocate_do(C, lib, lapp_data, reports, true); wm_link_append_data_free(lapp_data); @@ -1162,7 +1176,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; } - lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload); + lib_relocate_do(C, lib, lapp_data, op->reports, do_reload); wm_link_append_data_free(lapp_data); -- cgit v1.2.3 From 5655b3d1c55a1fb631a8eb40ac96d875b2ab213d Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 13 Aug 2021 15:45:07 -0300 Subject: Cleanup: fix typos in static variables _desps --> _deps --- source/blender/draw/intern/draw_cache_impl_mesh.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 359788545e4..86c14330409 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -95,7 +95,7 @@ #define MDEPS_CREATE(buff_name, ...) [_BUFFER_INDEX(buff_name)] = VA_NARGS_CALL_OVERLOAD(_MDEPS_CREATE, __VA_ARGS__) -#define _MDEPS_CREATE_MAP1(a) g_buffer_desps[_BUFFER_INDEX(a)] +#define _MDEPS_CREATE_MAP1(a) g_buffer_deps[_BUFFER_INDEX(a)] #define _MDEPS_CREATE_MAP2(a, b) _MDEPS_CREATE_MAP1(a) | _MDEPS_CREATE_MAP1(b) #define _MDEPS_CREATE_MAP3(a, b, c) _MDEPS_CREATE_MAP2(a, b) | _MDEPS_CREATE_MAP1(c) #define _MDEPS_CREATE_MAP4(a, b, c, d) _MDEPS_CREATE_MAP3(a, b, c) | _MDEPS_CREATE_MAP1(d) @@ -110,8 +110,8 @@ #ifndef NDEBUG # define _MDEPS_ASSERT2(b, name) \ - g_buffer_desps_d[_BUFFER_INDEX(name)] |= _MDEPS_CREATE1(b); \ - BLI_assert(g_buffer_desps[_BUFFER_INDEX(name)] & _MDEPS_CREATE1(b)) + g_buffer_deps_d[_BUFFER_INDEX(name)] |= _MDEPS_CREATE1(b); \ + BLI_assert(g_buffer_deps[_BUFFER_INDEX(name)] & _MDEPS_CREATE1(b)) # define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2) # define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3) # define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4) @@ -120,7 +120,7 @@ # define _MDEPS_ASSERT8(b, n1, n2, n3, n4, n5, n6, n7) _MDEPS_ASSERT7(b, n1, n2, n3, n4, n5, n6); _MDEPS_ASSERT2(b, n7) # define MDEPS_ASSERT(...) VA_NARGS_CALL_OVERLOAD(_MDEPS_ASSERT, __VA_ARGS__) -# define MDEPS_ASSERT_MAP(name) BLI_assert(g_buffer_desps_d[_BUFFER_INDEX(name)] == g_buffer_desps[_BUFFER_INDEX(name)]) +# define MDEPS_ASSERT_MAP(name) BLI_assert(g_buffer_deps_d[_BUFFER_INDEX(name)] == g_buffer_deps[_BUFFER_INDEX(name)]) #else # define MDEPS_ASSERT(...) # define MDEPS_ASSERT_MAP(name) @@ -128,7 +128,7 @@ /* clang-format on */ -static const DRWBatchFlag g_buffer_desps[] = { +static const DRWBatchFlag g_buffer_deps[] = { MDEPS_CREATE(vbo.pos_nor, batch.surface, batch.surface_weights, @@ -215,7 +215,7 @@ static const DRWBatchFlag g_buffer_desps[] = { }; #ifndef NDEBUG -static DRWBatchFlag g_buffer_desps_d[sizeof(g_buffer_desps)] = {0}; +static DRWBatchFlag g_buffer_deps_d[sizeof(g_buffer_deps)] = {0}; #endif static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache); -- cgit v1.2.3 From 0ed2df81cc3878d83a179ade256ba2d690ce9cde Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 13 Aug 2021 15:51:02 -0300 Subject: Fix T90637: Outliner: VSE context menu options are not working Some of the enum options in the context menu operations are not supported for all element types. `TSE_SEQUENCE`, for example, only supports the `Select` option. So, populate the enum list dynamically depending on the type. Also add some calls that were missing for the `TSE_SEQUENCE` type. (`WM_event_add_notifier` and `ED_undo_push`). --- .../editors/space_outliner/outliner_tools.c | 80 +++++++++++++++++----- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index a994368a0ec..2474b54384d 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -78,6 +78,8 @@ #include "ED_sequencer.h" #include "ED_undo.h" +#include "SEQ_relations.h" + #include "WM_api.h" #include "WM_message.h" #include "WM_types.h" @@ -1281,18 +1283,31 @@ static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), } } -static void sequence_fn(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr) +static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr) { Sequence *seq = (Sequence *)te->directdata; - if (event == OL_DOP_SELECT) { - Scene *scene = (Scene *)scene_ptr; - Editing *ed = SEQ_editing_get(scene, false); - if (BLI_findindex(ed->seqbasep, seq) != -1) { + Scene *scene = (Scene *)scene_ptr; + Editing *ed = SEQ_editing_get(scene, false); + if (BLI_findindex(ed->seqbasep, seq) != -1) { + if (event == OL_DOP_SELECT) { ED_sequencer_select_sequence_single(scene, seq, true); } + else if (event == OL_DOP_DESELECT) { + seq->flag &= ~SELECT; + } + else if (event == OL_DOP_HIDE) { + if (!(seq->flag & SEQ_MUTE)) { + seq->flag |= SEQ_MUTE; + SEQ_relations_invalidate_dependent(scene, seq); + } + } + else if (event == OL_DOP_UNHIDE) { + if (seq->flag & SEQ_MUTE) { + seq->flag &= ~SEQ_MUTE; + SEQ_relations_invalidate_dependent(scene, seq); + } + } } - - (void)tselem; } static void gpencil_layer_fn(int event, @@ -2709,16 +2724,6 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /** \name Data Menu Operator * \{ */ -/* XXX: select linked is for RNA structs only. */ -static const EnumPropertyItem prop_data_op_types[] = { - {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, - {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, - {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, - {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, - {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, - {0, NULL, 0, NULL, NULL}, -}; - static int outliner_data_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); @@ -2762,6 +2767,8 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); outliner_do_data_operation( space_outliner, datalevel, event, &space_outliner->tree, sequence_fn, scene); + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); + ED_undo_push(C, "Sequencer operation"); break; } @@ -2789,6 +2796,42 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +/* Dynamically populate an enum of Keying Sets */ +static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *UNUSED(r_free)) +{ + /* Check for invalid states. */ + if (C == NULL) { + return DummyRNA_DEFAULT_items; + } + + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + if (space_outliner == NULL) { + return DummyRNA_DEFAULT_items; + } + + static const EnumPropertyItem optype_sel_and_hide[] = { + {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, + {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, + {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, + {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem optype_sel_linked[] = { + {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}}; + + TreeElement *te = get_target_element(space_outliner); + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->type == TSE_RNA_STRUCT) { + return optype_sel_linked; + } + + return optype_sel_and_hide; +} + void OUTLINER_OT_data_operation(wmOperatorType *ot) { /* identifiers */ @@ -2802,7 +2845,8 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Data Operation", ""); + RNA_def_enum_funcs(ot->prop, outliner_data_op_sets_enum_item_fn); } /** \} */ -- cgit v1.2.3 From ae3472998abd8e564e49741f84a9ed9354954e04 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 13 Aug 2021 17:36:35 -0300 Subject: Cleanup: rearrange includes Bring the includes from the same project together. --- source/blender/editors/space_outliner/outliner_tools.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 2474b54384d..d88ae82cc9a 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -78,8 +78,6 @@ #include "ED_sequencer.h" #include "ED_undo.h" -#include "SEQ_relations.h" - #include "WM_api.h" #include "WM_message.h" #include "WM_types.h" @@ -94,6 +92,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" #include "outliner_intern.h" -- cgit v1.2.3 From 6a4533dd02c053fc24738fdd285b398e3d7767c1 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 13 Aug 2021 14:31:10 -0700 Subject: BLF Cleanup: Size Defines, Comments, etc This patch makes some non-functional changes to BLF code. Some size defines added, comments changed, simplification of macro BLF_KERNING_VARS. See D12200 for more details. Differential Revision: https://developer.blender.org/D12200 Reviewed by Campbell Barton --- source/blender/blenfont/intern/blf_font.c | 19 +++++++++---------- source/blender/blenfont/intern/blf_glyph.c | 7 ++----- .../blender/blenfont/intern/blf_internal_types.h | 22 +++++++++++++--------- 3 files changed, 24 insertions(+), 24 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 8e306730e3c..0dfb2e843c9 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -318,7 +318,7 @@ static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc) if (glyph_ascii_table['0'] == NULL) { GlyphBLF *g; /* Skip control characters and just cache rendered glyphs for visible ASCII range. */ - for (uint i = 32; i < 128; i++) { + for (uint i = GLYPH_ASCII_CACHE_MIN; i <= GLYPH_ASCII_CACHE_MAX; i++) { g = blf_glyph_search(gc, i); if (!g) { FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); @@ -355,7 +355,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, /* NOTE: `blf_font_ensure_ascii_table(font, gc);` must be called before this macro. */ #define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \ - if (((_c) = (_str)[_i]) < 0x80) { \ + if (((_c) = (_str)[_i]) < GLYPH_ASCII_TABLE_SIZE) { \ _g = (_glyph_ascii_table)[_c]; \ _i++; \ } \ @@ -370,11 +370,10 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, (void)0 #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \ - const bool _has_kerning = FT_HAS_KERNING((_font)->face) != 0; \ - const FT_UInt _kern_mode = (_has_kerning == 0) ? 0 : \ - (((_font)->flags & BLF_KERNING_DEFAULT) ? \ - ft_kerning_default : \ - (FT_UInt)FT_KERNING_UNFITTED) + const bool _has_kerning = FT_HAS_KERNING((_font)->face); \ + const FT_UInt _kern_mode = (_has_kerning && !((_font)->flags & BLF_KERNING_DEFAULT)) ? \ + FT_KERNING_UNFITTED : \ + FT_KERNING_DEFAULT; /* NOTE: `blf_font_ensure_ascii_kerning(font, gc, kern_mode);` must be called before this macro. */ @@ -382,7 +381,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, { \ if (_g_prev) { \ FT_Vector _delta; \ - if (_c_prev < 0x80 && _c < 0x80) { \ + if (_c_prev < KERNING_CACHE_TABLE_SIZE && _c < GLYPH_ASCII_TABLE_SIZE) { \ _pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \ } \ else if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == \ @@ -482,7 +481,7 @@ static void blf_font_draw_ascii_ex( blf_batch_draw_begin(font); while ((c = *(str++)) && len--) { - BLI_assert(c < 128); + BLI_assert(c < GLYPH_ASCII_TABLE_SIZE); if ((g = glyph_ascii_table[c]) == NULL) { continue; } @@ -1262,7 +1261,7 @@ int blf_font_count_missing_chars(FontBLF *font, while (i < len) { unsigned int c; - if ((c = str[i]) < 0x80) { + if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) { i++; } else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) { diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 3f01501fda4..35938a7d5c3 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -80,8 +80,8 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) kc->mode = font->kerning_mode; unsigned int i, j; - for (i = 0; i < 0x80; i++) { - for (j = 0; j < 0x80; j++) { + for (i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { + for (j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { GlyphBLF *g = blf_glyph_search(gc, i); if (!g) { FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); @@ -144,8 +144,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); - gc->glyphs_len_max = (int)font->face->num_glyphs; - gc->glyphs_len_free = (int)font->face->num_glyphs; gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f; gc->descender = ((float)font->face->size->metrics.descender) / 64.0f; @@ -514,7 +512,6 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, (size_t)buff_size); gc->bitmap_len = bitmap_len; - gc->glyphs_len_free--; g->glyph_cache = gc; } diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 6816c97321d..1cd004ce77f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -28,6 +28,16 @@ #define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */ +/* Number of characters in GlyphCacheBLF.glyph_ascii_table. */ +#define GLYPH_ASCII_TABLE_SIZE 128 + +/* First and last characters (inclusive) of range to cache within GLYPH_ASCII_TABLE_SIZE. */ +#define GLYPH_ASCII_CACHE_MIN 32 /* Space */ +#define GLYPH_ASCII_CACHE_MAX 126 /* Tilde */ + +/* Number of characters in KerningCacheBLF.table. */ +#define KERNING_CACHE_TABLE_SIZE 128 + typedef struct BatchBLF { struct FontBLF *font; /* can only batch glyph from the same font */ struct GPUBatch *batch; @@ -51,7 +61,7 @@ typedef struct KerningCacheBLF { /* only cache a ascii glyph pairs. Only store the x * offset we are interested in, instead of the full FT_Vector. */ - int table[0x80][0x80]; + int table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]; } KerningCacheBLF; typedef struct GlyphCacheBLF { @@ -71,7 +81,7 @@ typedef struct GlyphCacheBLF { ListBase bucket[257]; /* fast ascii lookup */ - struct GlyphBLF *glyph_ascii_table[128]; + struct GlyphBLF *glyph_ascii_table[GLYPH_ASCII_TABLE_SIZE]; /* texture array, to draw the glyphs. */ GPUTexture *texture; @@ -84,12 +94,6 @@ typedef struct GlyphCacheBLF { int glyph_width_max; int glyph_height_max; - /* number of glyphs in the font. */ - int glyphs_len_max; - - /* number of glyphs not yet loaded (decreases every glyph loaded). */ - int glyphs_len_free; - /* ascender and descender value. */ float ascender; float descender; @@ -99,7 +103,7 @@ typedef struct GlyphBLF { struct GlyphBLF *next; struct GlyphBLF *prev; - /* and the character, as UTF8 */ + /* and the character, as UTF-32 */ unsigned int c; /* freetype2 index, to speed-up the search. */ -- cgit v1.2.3 From 8f2b60ddbfea800ac155d9419e8d237c791fcda9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 13 Aug 2021 21:46:59 -0500 Subject: Cleanup: Variable names, formatting, reduce indentation --- .../nodes/geometry/nodes/node_geo_raycast.cc | 152 ++++++++++----------- 1 file changed, 76 insertions(+), 76 deletions(-) (limited to 'source/blender') diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index 0c1d8645411..88e3bf17d43 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -63,20 +63,20 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } +namespace blender::nodes { + static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; - blender::nodes::update_attribute_input_socket_availabilities( + update_attribute_input_socket_availabilities( *node, "Ray Direction", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction); - blender::nodes::update_attribute_input_socket_availabilities( + update_attribute_input_socket_availabilities( *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); } -namespace blender::nodes { - -static void raycast_to_mesh(const Mesh *mesh, +static void raycast_to_mesh(const Mesh &mesh, const VArray &ray_origins, const VArray &ray_directions, const VArray &ray_lengths, @@ -95,62 +95,64 @@ static void raycast_to_mesh(const Mesh *mesh, BLI_assert(ray_origins.size() == r_hit_distances.size() || r_hit_distances.is_empty()); BVHTreeFromMesh tree_data; - BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_LOOPTRI, 4); - - if (tree_data.tree != nullptr) { - for (const int i : ray_origins.index_range()) { - const float ray_length = ray_lengths[i]; - const float3 ray_origin = ray_origins[i]; - const float3 ray_direction = ray_directions[i].normalized(); - - BVHTreeRayHit hit; - hit.index = -1; - hit.dist = ray_length; - if (BLI_bvhtree_ray_cast(tree_data.tree, - ray_origin, - ray_direction, - 0.0f, - &hit, - tree_data.raycast_callback, - &tree_data) != -1) { - if (!r_hit.is_empty()) { - r_hit[i] = hit.index >= 0; - } - if (!r_hit_indices.is_empty()) { - /* Index should always be a valid looptri index, use 0 when hit failed. */ - r_hit_indices[i] = max_ii(hit.index, 0); - } - if (!r_hit_positions.is_empty()) { - r_hit_positions[i] = hit.co; - } - if (!r_hit_normals.is_empty()) { - r_hit_normals[i] = hit.no; - } - if (!r_hit_distances.is_empty()) { - r_hit_distances[i] = hit.dist; - } + BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4); + if (tree_data.tree == nullptr) { + free_bvhtree_from_mesh(&tree_data); + return; + } + + for (const int i : ray_origins.index_range()) { + const float ray_length = ray_lengths[i]; + const float3 ray_origin = ray_origins[i]; + const float3 ray_direction = ray_directions[i].normalized(); + + BVHTreeRayHit hit; + hit.index = -1; + hit.dist = ray_length; + if (BLI_bvhtree_ray_cast(tree_data.tree, + ray_origin, + ray_direction, + 0.0f, + &hit, + tree_data.raycast_callback, + &tree_data) != -1) { + if (!r_hit.is_empty()) { + r_hit[i] = hit.index >= 0; + } + if (!r_hit_indices.is_empty()) { + /* Index should always be a valid looptri index, use 0 when hit failed. */ + r_hit_indices[i] = max_ii(hit.index, 0); + } + if (!r_hit_positions.is_empty()) { + r_hit_positions[i] = hit.co; } - else { - if (!r_hit.is_empty()) { - r_hit[i] = false; - } - if (!r_hit_indices.is_empty()) { - r_hit_indices[i] = 0; - } - if (!r_hit_positions.is_empty()) { - r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f); - } - if (!r_hit_normals.is_empty()) { - r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f); - } - if (!r_hit_distances.is_empty()) { - r_hit_distances[i] = ray_length; - } + if (!r_hit_normals.is_empty()) { + r_hit_normals[i] = hit.no; + } + if (!r_hit_distances.is_empty()) { + r_hit_distances[i] = hit.dist; + } + } + else { + if (!r_hit.is_empty()) { + r_hit[i] = false; + } + if (!r_hit_indices.is_empty()) { + r_hit_indices[i] = 0; + } + if (!r_hit_positions.is_empty()) { + r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f); + } + if (!r_hit_normals.is_empty()) { + r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f); + } + if (!r_hit_distances.is_empty()) { + r_hit_distances[i] = ray_length; } } - - free_bvhtree_from_mesh(&tree_data); } + + free_bvhtree_from_mesh(&tree_data); } static bke::mesh_surface_sample::eAttributeMapMode get_map_mode( @@ -166,7 +168,7 @@ static bke::mesh_surface_sample::eAttributeMapMode get_map_mode( } static void raycast_from_points(const GeoNodeExecParams ¶ms, - const GeometrySet &src_geometry, + const GeometrySet &target_geometry, GeometryComponent &dst_component, const StringRef hit_name, const StringRef hit_position_name, @@ -177,7 +179,8 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, { BLI_assert(hit_attribute_names.size() == hit_attribute_output_names.size()); - const MeshComponent *src_mesh_component = src_geometry.get_component_for_read(); + const MeshComponent *src_mesh_component = + target_geometry.get_component_for_read(); if (src_mesh_component == nullptr) { return; } @@ -211,8 +214,7 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, dst_component.attribute_try_get_for_output_only(hit_distance_name, result_domain); /* Positions and looptri indices are always needed for interpolation, - * so create temporary arrays if no output attribute is given. - */ + * so create temporary arrays if no output attribute is given. */ Array hit_indices; Array hit_positions_internal; if (!hit_attribute_names.is_empty()) { @@ -232,7 +234,7 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, hit_distance_attribute.as_span() : MutableSpan(); - raycast_to_mesh(src_mesh, + raycast_to_mesh(*src_mesh, ray_origins, ray_directions, ray_lengths, @@ -268,34 +270,32 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, static void geo_node_raycast_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); - GeometrySet cast_geometry_set = params.extract_input("Target Geometry"); + GeometrySet target_geometry_set = params.extract_input("Target Geometry"); const std::string hit_name = params.extract_input("Is Hit"); const std::string hit_position_name = params.extract_input("Hit Position"); const std::string hit_normal_name = params.extract_input("Hit Normal"); const std::string hit_distance_name = params.extract_input("Hit Distance"); - const Array hit_attribute_names = { - params.extract_input("Target Attribute")}; - const Array hit_attribute_output_names = { - params.extract_input("Hit Attribute")}; + const Array hit_names = {params.extract_input("Target Attribute")}; + const Array hit_output_names = {params.extract_input("Hit Attribute")}; geometry_set = bke::geometry_set_realize_instances(geometry_set); - cast_geometry_set = bke::geometry_set_realize_instances(cast_geometry_set); + target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set); - static const Array SupportedTypes = { + static const Array types = { GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; - for (GeometryComponentType geo_type : SupportedTypes) { - if (geometry_set.has(geo_type)) { + for (const GeometryComponentType type : types) { + if (geometry_set.has(type)) { raycast_from_points(params, - cast_geometry_set, - geometry_set.get_component_for_write(geo_type), + target_geometry_set, + geometry_set.get_component_for_write(type), hit_name, hit_position_name, hit_normal_name, hit_distance_name, - hit_attribute_names, - hit_attribute_output_names); + hit_names, + hit_output_names); } } @@ -312,7 +312,7 @@ void register_node_type_geo_raycast() node_type_socket_templates(&ntype, geo_node_raycast_in, geo_node_raycast_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, geo_node_raycast_init); - node_type_update(&ntype, geo_node_raycast_update); + node_type_update(&ntype, blender::nodes::geo_node_raycast_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; -- cgit v1.2.3 From d5261e973b5624b40b80771903e9d2a0c9ff37e4 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Sat, 14 Aug 2021 13:50:51 -0700 Subject: BLF: Do Not Preload Glyph Cache This patch turns off the preloading of ascii glyphs and instead caches each glyph the first time it is actually used. See D12215 for much more detail. Differential Revision: https://developer.blender.org/D12215 Reviewed by Campbell Barton --- source/blender/blenfont/intern/blf_font.c | 77 ++++++---------------- .../blender/blenfont/intern/blf_internal_types.h | 4 -- 2 files changed, 19 insertions(+), 62 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 0dfb2e843c9..28039ff11ac 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -308,29 +308,6 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) blf_glyph_cache_release(font); } -static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc) -{ - GlyphBLF **glyph_ascii_table; - - glyph_ascii_table = gc->glyph_ascii_table; - - /* build ascii on demand */ - if (glyph_ascii_table['0'] == NULL) { - GlyphBLF *g; - /* Skip control characters and just cache rendered glyphs for visible ASCII range. */ - for (uint i = GLYPH_ASCII_CACHE_MIN; i <= GLYPH_ASCII_CACHE_MAX; i++) { - g = blf_glyph_search(gc, i); - if (!g) { - FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); - g = blf_glyph_add(font, gc, glyph_index, i); - } - glyph_ascii_table[i] = g; - } - } - - return glyph_ascii_table; -} - static void blf_font_ensure_ascii_kerning(FontBLF *font, GlyphCacheBLF *gc, const FT_UInt kern_mode) @@ -352,11 +329,12 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, * characters. */ -/* NOTE: `blf_font_ensure_ascii_table(font, gc);` must be called before this macro. */ - -#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \ +#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c) \ if (((_c) = (_str)[_i]) < GLYPH_ASCII_TABLE_SIZE) { \ - _g = (_glyph_ascii_table)[_c]; \ + if ((_g = (_gc->glyph_ascii_table)[_c]) == NULL) { \ + _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \ + _gc->glyph_ascii_table[_c] = _g; \ + } \ _i++; \ } \ else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \ @@ -420,8 +398,6 @@ static void blf_font_draw_ex(FontBLF *font, return; } - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); - BLF_KERNING_VARS(font, has_kerning, kern_mode); blf_font_ensure_ascii_kerning(font, gc, kern_mode); @@ -429,7 +405,7 @@ static void blf_font_draw_ex(FontBLF *font, blf_batch_draw_begin(font); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -472,7 +448,6 @@ static void blf_font_draw_ascii_ex( int pen_x = 0; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -482,8 +457,11 @@ static void blf_font_draw_ascii_ex( while ((c = *(str++)) && len--) { BLI_assert(c < GLYPH_ASCII_TABLE_SIZE); - if ((g = glyph_ascii_table[c]) == NULL) { - continue; + if ((g = gc->glyph_ascii_table[c]) == NULL) { + g = blf_glyph_add(font, gc, FT_Get_Char_Index((font)->face, c), c); + if ((gc->glyph_ascii_table[c] = g) == NULL) { + continue; + } } if (has_kerning) { BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); @@ -522,12 +500,11 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) size_t i = 0; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); blf_batch_draw_begin(font); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -568,8 +545,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, int pen_y_basis = (int)font->pos[1] + pen_y; size_t i = 0; - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); - /* buffer specific vars */ FontBufInfoBLF *buf_info = &font->buf_info; const float *b_col_float = buf_info->col_float; @@ -584,7 +559,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* another buffer specific call for color conversion */ while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -741,7 +716,6 @@ size_t blf_font_width_to_strlen( size_t i, i_prev; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); const int width_i = (int)width; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -752,7 +726,7 @@ size_t blf_font_width_to_strlen( for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i]; i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (blf_font_width_to_strlen_glyph_process( font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) { @@ -778,7 +752,6 @@ size_t blf_font_width_to_rstrlen( char *s, *s_prev; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); const int width_i = (int)width; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -794,7 +767,7 @@ size_t blf_font_width_to_rstrlen( i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0); i_tmp = i; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c); for (width_new = pen_x = 0; (s != NULL); i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { s_prev = BLI_str_find_prev_char_utf8(str, s); @@ -802,7 +775,7 @@ size_t blf_font_width_to_rstrlen( if (s_prev != NULL) { i_tmp = i_prev; - BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev); BLI_assert(i_tmp == i); } @@ -832,9 +805,6 @@ static void blf_font_boundbox_ex(FontBLF *font, GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0; - - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); - rctf gbox; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -847,7 +817,7 @@ static void blf_font_boundbox_ex(FontBLF *font, blf_font_ensure_ascii_kerning(font, gc, kern_mode); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -937,7 +907,6 @@ static void blf_font_wrap_apply(FontBLF *font, int pen_x_next = 0; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -953,7 +922,7 @@ static void blf_font_wrap_apply(FontBLF *font, size_t i_curr = i; bool do_draw = false; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -1154,8 +1123,6 @@ float blf_font_fixed_width(FontBLF *font) const unsigned int c = ' '; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_table(font, gc); - GlyphBLF *g = blf_glyph_search(gc, c); if (!g) { g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c); @@ -1195,15 +1162,13 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, return; } - GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc); - BLF_KERNING_VARS(font, has_kerning, kern_mode); blf_font_ensure_ascii_kerning(font, gc, kern_mode); while ((i < len) && str[i]) { i_curr = i; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table); + BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -1429,7 +1394,6 @@ int blf_font_height_max(FontBLF *font) int height_max; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_table(font, gc); height_max = gc->glyph_height_max; blf_glyph_cache_release(font); @@ -1441,7 +1405,6 @@ int blf_font_width_max(FontBLF *font) int width_max; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_table(font, gc); width_max = gc->glyph_width_max; blf_glyph_cache_release(font); @@ -1453,7 +1416,6 @@ float blf_font_descender(FontBLF *font) float descender; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_table(font, gc); descender = gc->descender; blf_glyph_cache_release(font); @@ -1465,7 +1427,6 @@ float blf_font_ascender(FontBLF *font) float ascender; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_table(font, gc); ascender = gc->ascender; blf_glyph_cache_release(font); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 1cd004ce77f..6bcacc62a30 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -31,10 +31,6 @@ /* Number of characters in GlyphCacheBLF.glyph_ascii_table. */ #define GLYPH_ASCII_TABLE_SIZE 128 -/* First and last characters (inclusive) of range to cache within GLYPH_ASCII_TABLE_SIZE. */ -#define GLYPH_ASCII_CACHE_MIN 32 /* Space */ -#define GLYPH_ASCII_CACHE_MAX 126 /* Tilde */ - /* Number of characters in KerningCacheBLF.table. */ #define KERNING_CACHE_TABLE_SIZE 128 -- cgit v1.2.3 From 3f0d785d23bf246abcb6f9cf86e106cdc9ac3636 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Sun, 15 Aug 2021 17:54:59 -0300 Subject: Fix T90658: selection of some 3D gizmos failing Small error due to wrong variable usage. Introduced in rBfcd2d63b644e. --- source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index b90e288776e..6f6a2402d89 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -627,7 +627,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, wmGizmo *gz = visible_gizmos[buf_iter[3] >> 8]; float co_3d[3]; co_screen[2] = int_as_float(buf_iter[1]); - GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); + GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d); float select_bias = gz->select_bias; if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { select_bias *= gz->scale_final; -- cgit v1.2.3 From 899935d5d02463187617d1adc5f0c0f41fe56265 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Sun, 15 Aug 2021 20:07:25 -0300 Subject: Fix wrong usage of 'sizeof' The intention was to use `ARRAY_SIZE`. No functional changes. --- source/blender/draw/intern/draw_cache_impl_mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 86c14330409..52b76733b78 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -215,7 +215,7 @@ static const DRWBatchFlag g_buffer_deps[] = { }; #ifndef NDEBUG -static DRWBatchFlag g_buffer_deps_d[sizeof(g_buffer_deps)] = {0}; +static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0}; #endif static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache); -- cgit v1.2.3 From eb278f5e12cf9db9664a89ed10902fb891846afe Mon Sep 17 00:00:00 2001 From: Peter Kim Date: Mon, 16 Aug 2021 11:46:09 +0900 Subject: XR: Color Depth Adjustments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This addresses reduced visibility of scenes (as displayed in the VR headset) that can result from the 8-bit color depth format currently used for XR swapchain images. By switching to a swapchain format with higher color depth (RGB10_A2, RGBA16, RGBA16F) for supported runtimes, visibility in VR should be noticeably improved. However, current limitations are lack of support for these higher color depth formats by some XR runtimes, especially for OpenGL. Also important to note that GPU_offscreen_create() now explicitly takes in the texture format (eGPUTextureFormat) instead of a "high_bitdepth" boolean. Reviewed By: Julian Eisel, Clément Foucault Differential Revision: http://developer.blender.org/D9842 --- source/blender/editors/gpencil/gpencil_fill.c | 3 ++- source/blender/editors/render/render_opengl.c | 2 +- source/blender/editors/screen/screen_draw.c | 2 +- source/blender/editors/space_view3d/view3d_draw.c | 2 +- source/blender/gpu/GPU_framebuffer.h | 2 +- source/blender/gpu/intern/gpu_framebuffer.cc | 5 ++--- source/blender/python/gpu/gpu_py_offscreen.c | 2 +- source/blender/windowmanager/intern/wm_draw.c | 4 ++-- .../windowmanager/xr/intern/wm_xr_session.c | 26 ++++++++++++++++++---- 9 files changed, 33 insertions(+), 15 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 67e1bd5294b..0c88d678ef4 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -646,7 +646,8 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) tgpf->sizey = (int)tgpf->region->winy; char err_out[256] = "unknown"; - GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, true, false, err_out); + GPUOffScreen *offscreen = GPU_offscreen_create( + tgpf->sizex, tgpf->sizey, true, GPU_RGBA8, err_out); if (offscreen == NULL) { printf("GPencil - Fill - Unable to create fill buffer\n"); return false; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index d3307ebf274..749010a5ba3 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -768,7 +768,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ DRW_opengl_context_enable(); /* Off-screen creation needs to be done in DRW context. */ - ofs = GPU_offscreen_create(sizex, sizey, true, true, err_out); + ofs = GPU_offscreen_create(sizex, sizey, true, GPU_RGBA16F, err_out); DRW_opengl_context_disable(); if (!ofs) { diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index dca464bbf22..ab50e327de3 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -451,7 +451,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect) { char err_out[256] = "unknown"; - GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, true, false, err_out); + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, true, GPU_RGBA8, err_out); GPU_offscreen_bind(offscreen, true); GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index d87c14b9844..ec99affe43b 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1876,7 +1876,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, true, false, err_out); + ofs = GPU_offscreen_create(sizex, sizey, true, GPU_RGBA8, err_out); if (ofs == NULL) { DRW_opengl_context_disable(); return NULL; diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 6482d9a9d3e..bf0ab3dc533 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -223,7 +223,7 @@ uint GPU_framebuffer_stack_level_get(void); */ GPUOffScreen *GPU_offscreen_create( - int width, int height, bool depth, bool high_bitdepth, char err_out[256]); + int width, int height, bool depth, eGPUTextureFormat format, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index a6f7d43e563..9099a6e4245 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -591,7 +591,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) } GPUOffScreen *GPU_offscreen_create( - int width, int height, bool depth, bool high_bitdepth, char err_out[256]) + int width, int height, bool depth, eGPUTextureFormat format, char err_out[256]) { GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__); @@ -600,8 +600,7 @@ GPUOffScreen *GPU_offscreen_create( height = max_ii(1, height); width = max_ii(1, width); - ofs->color = GPU_texture_create_2d( - "ofs_color", width, height, 1, (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, nullptr); + ofs->color = GPU_texture_create_2d("ofs_color", width, height, 1, format, nullptr); if (depth) { ofs->depth = GPU_texture_create_2d( diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 32053df5e97..6f23c2213e2 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -227,7 +227,7 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self), } if (GPU_context_active_get()) { - ofs = GPU_offscreen_create(width, height, true, false, err_out); + ofs = GPU_offscreen_create(width, height, true, GPU_RGBA8, err_out); } else { STRNCPY(err_out, "No active GPU context found"); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index f01e28f8822..dcb918747f3 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -455,7 +455,7 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_ * depth or multisample buffers. 3D view creates own buffers with * the data it needs. */ GPUOffScreen *offscreen = GPU_offscreen_create( - region->winx, region->winy, false, false, NULL); + region->winx, region->winy, false, GPU_RGBA8, NULL); if (!offscreen) { WM_report(RPT_ERROR, "Region could not be drawn!"); return; @@ -888,7 +888,7 @@ static void wm_draw_window(bContext *C, wmWindow *win) * stereo methods, but it's less efficient than drawing directly. */ const int width = WM_window_pixels_x(win); const int height = WM_window_pixels_y(win); - GPUOffScreen *offscreen = GPU_offscreen_create(width, height, false, false, NULL); + GPUOffScreen *offscreen = GPU_offscreen_create(width, height, false, GPU_RGBA8, NULL); if (offscreen) { GPUTexture *texture = GPU_offscreen_color_texture(offscreen); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index dd9cac2bb16..ba30b0dd864 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -657,9 +657,6 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, GPUViewport *viewport = vp->viewport; const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) && (GPU_offscreen_height(offscreen) != draw_view->height); - char err_out[256] = "unknown"; - bool failure = false; - if (offscreen) { BLI_assert(viewport); @@ -670,8 +667,29 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, GPU_offscreen_free(offscreen); } + char err_out[256] = "unknown"; + bool failure = false; + eGPUTextureFormat format = + GPU_R8; /* Initialize with some unsupported format to check following switch statement. */ + + switch (draw_view->swapchain_format) { + case GHOST_kXrSwapchainFormatRGBA8: + format = GPU_RGBA8; + break; + case GHOST_kXrSwapchainFormatRGBA16: + format = GPU_RGBA16; + break; + case GHOST_kXrSwapchainFormatRGBA16F: + format = GPU_RGBA16F; + break; + case GHOST_kXrSwapchainFormatRGB10_A2: + format = GPU_RGB10_A2; + break; + } + BLI_assert(format != GPU_R8); + offscreen = vp->offscreen = GPU_offscreen_create( - draw_view->width, draw_view->height, true, false, err_out); + draw_view->width, draw_view->height, true, format, err_out); if (offscreen) { viewport = vp->viewport = GPU_viewport_create(); if (!viewport) { -- cgit v1.2.3 From 6aebbe6a0a2a52df3ff127b6ad28da494661b992 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 13:44:02 +1000 Subject: Cleanup: replace macros with inline functions for font drawing Also assert blf_font_ensure_ascii_kerning has been called in blf_kerning_step_fast. --- source/blender/blenfont/intern/blf_font.c | 140 ++++++++++++++++-------------- 1 file changed, 77 insertions(+), 63 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 28039ff11ac..a0c146a974d 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -329,23 +329,29 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, * characters. */ -#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c) \ - if (((_c) = (_str)[_i]) < GLYPH_ASCII_TABLE_SIZE) { \ - if ((_g = (_gc->glyph_ascii_table)[_c]) == NULL) { \ - _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \ - _gc->glyph_ascii_table[_c] = _g; \ - } \ - _i++; \ - } \ - else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \ - if ((_g = blf_glyph_search(_gc, _c)) == NULL) { \ - _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \ - } \ - } \ - else { \ - _g = NULL; \ - } \ - (void)0 +BLI_INLINE GlyphBLF *blf_utf8_next_fast( + FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t *i_p, uint *r_c) +{ + GlyphBLF *g; + if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) { + g = (gc->glyph_ascii_table)[*r_c]; + if (UNLIKELY(g == NULL)) { + g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); + gc->glyph_ascii_table[*r_c] = g; + } + (*i_p)++; + } + else if ((*r_c = BLI_str_utf8_as_unicode_step(str, i_p)) != BLI_UTF8_ERR) { + g = blf_glyph_search(gc, *r_c); + if (UNLIKELY(g == NULL)) { + g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); + } + } + else { + g = NULL; + } + return g; +} #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \ const bool _has_kerning = FT_HAS_KERNING((_font)->face); \ @@ -353,33 +359,40 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font, FT_KERNING_UNFITTED : \ FT_KERNING_DEFAULT; -/* NOTE: `blf_font_ensure_ascii_kerning(font, gc, kern_mode);` must be called before this macro. */ - -#define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \ - { \ - if (_g_prev) { \ - FT_Vector _delta; \ - if (_c_prev < KERNING_CACHE_TABLE_SIZE && _c < GLYPH_ASCII_TABLE_SIZE) { \ - _pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \ - } \ - else if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == \ - 0) { \ - _pen_x += (int)_delta.x >> 6; \ - } \ - } \ - } \ - (void)0 - -#define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x) \ - { \ - if (_g_prev) { \ - _delta.x = _delta.y = 0; \ - if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == 0) { \ - _pen_x += (int)_delta.x >> 6; \ - } \ - } \ - } \ - (void)0 +BLI_INLINE void blf_kerning_step_fast(FontBLF *font, + const FT_UInt kern_mode, + const GlyphBLF *g_prev, + const GlyphBLF *g, + const uint c_prev, + const uint c, + int *pen_x_p) +{ + /* `blf_font_ensure_ascii_kerning(font, gc, kern_mode);` must be called before this function. */ + BLI_assert((font->kerning_mode == kern_mode) && (font->kerning_cache != NULL)); + + if (g_prev != NULL) { + if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { + *pen_x_p += font->kerning_cache->table[c][c_prev]; + } + else { + FT_Vector delta; + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kern_mode, &delta) == 0) { + *pen_x_p += (int)delta.x >> 6; + } + } + } +} + +BLI_INLINE void blf_kerning_step( + FontBLF *font, const FT_UInt kern_mode, const GlyphBLF *g_prev, const GlyphBLF *g, int *pen_x) +{ + if (g_prev != NULL) { + FT_Vector delta; + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kern_mode, &delta) == 0) { + *pen_x += (int)delta.x >> 6; + } + } +} static void blf_font_draw_ex(FontBLF *font, GlyphCacheBLF *gc, @@ -405,7 +418,7 @@ static void blf_font_draw_ex(FontBLF *font, blf_batch_draw_begin(font); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -414,7 +427,7 @@ static void blf_font_draw_ex(FontBLF *font, continue; } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } /* do not return this loop if clipped, we want every character tested */ @@ -457,14 +470,16 @@ static void blf_font_draw_ascii_ex( while ((c = *(str++)) && len--) { BLI_assert(c < GLYPH_ASCII_TABLE_SIZE); - if ((g = gc->glyph_ascii_table[c]) == NULL) { + g = gc->glyph_ascii_table[c]; + if (UNLIKELY(g == NULL)) { g = blf_glyph_add(font, gc, FT_Get_Char_Index((font)->face, c), c); - if ((gc->glyph_ascii_table[c] = g) == NULL) { + gc->glyph_ascii_table[c] = g; + if (UNLIKELY(g == NULL)) { continue; } } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } /* do not return this loop if clipped, we want every character tested */ @@ -504,7 +519,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_batch_draw_begin(font); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -559,7 +574,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* another buffer specific call for color conversion */ while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -568,7 +583,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, continue; } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } chx = pen_x + ((int)g->pos[0]); @@ -699,7 +714,7 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, return false; /* continue the calling loop. */ } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, *pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, pen_x); } *pen_x += g->advance_i; @@ -726,7 +741,7 @@ size_t blf_font_width_to_strlen( for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i]; i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (blf_font_width_to_strlen_glyph_process( font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) { @@ -767,7 +782,7 @@ size_t blf_font_width_to_rstrlen( i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0); i_tmp = i; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c); + g = blf_utf8_next_fast(font, gc, str, &i_tmp, &c); for (width_new = pen_x = 0; (s != NULL); i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { s_prev = BLI_str_find_prev_char_utf8(str, s); @@ -775,7 +790,7 @@ size_t blf_font_width_to_rstrlen( if (s_prev != NULL) { i_tmp = i_prev; - BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev); + g_prev = blf_utf8_next_fast(font, gc, str, &i_tmp, &c_prev); BLI_assert(i_tmp == i); } @@ -817,7 +832,7 @@ static void blf_font_boundbox_ex(FontBLF *font, blf_font_ensure_ascii_kerning(font, gc, kern_mode); while ((i < len) && str[i]) { - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -826,7 +841,7 @@ static void blf_font_boundbox_ex(FontBLF *font, continue; } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } gbox.xmin = (float)pen_x; @@ -900,7 +915,6 @@ static void blf_font_wrap_apply(FontBLF *font, { unsigned int c; GlyphBLF *g, *g_prev = NULL; - FT_Vector delta; int pen_x = 0, pen_y = 0; size_t i = 0; int lines = 0; @@ -922,7 +936,7 @@ static void blf_font_wrap_apply(FontBLF *font, size_t i_curr = i; bool do_draw = false; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -931,7 +945,7 @@ static void blf_font_wrap_apply(FontBLF *font, continue; } if (has_kerning) { - BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + blf_kerning_step(font, kern_mode, g_prev, g, &pen_x); } /** @@ -1168,7 +1182,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, while ((i < len) && str[i]) { i_curr = i; - BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c); + g = blf_utf8_next_fast(font, gc, str, &i, &c); if (UNLIKELY(c == BLI_UTF8_ERR)) { break; @@ -1177,7 +1191,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, continue; } if (has_kerning) { - BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } gbox.xmin = pen_x; -- cgit v1.2.3 From 87adcbc94fc78d2c227aff992d045b287fcf2337 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 13:57:54 +1000 Subject: BLF: use fast ASCII kerning for word-wrap calculations While this wasn't a bottleneck, using the fast version of this function removes some duplicate code that doesn't use the look-up table. --- source/blender/blenfont/intern/blf_font.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index a0c146a974d..512e2babf74 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -383,17 +383,6 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, } } -BLI_INLINE void blf_kerning_step( - FontBLF *font, const FT_UInt kern_mode, const GlyphBLF *g_prev, const GlyphBLF *g, int *pen_x) -{ - if (g_prev != NULL) { - FT_Vector delta; - if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kern_mode, &delta) == 0) { - *pen_x += (int)delta.x >> 6; - } - } -} - static void blf_font_draw_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, @@ -913,7 +902,7 @@ static void blf_font_wrap_apply(FontBLF *font, void *userdata), void *userdata) { - unsigned int c; + unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0, pen_y = 0; size_t i = 0; @@ -924,6 +913,8 @@ static void blf_font_wrap_apply(FontBLF *font, BLF_KERNING_VARS(font, has_kerning, kern_mode); + blf_font_ensure_ascii_kerning(font, gc, kern_mode); + struct WordWrapVars { int wrap_width; size_t start, last[2]; @@ -945,7 +936,7 @@ static void blf_font_wrap_apply(FontBLF *font, continue; } if (has_kerning) { - blf_kerning_step(font, kern_mode, g_prev, g, &pen_x); + blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); } /** @@ -986,12 +977,14 @@ static void blf_font_wrap_apply(FontBLF *font, pen_x = 0; pen_y -= gc->glyph_height_max; g_prev = NULL; + c_prev = BLI_UTF8_ERR; lines += 1; continue; } pen_x = pen_x_next; g_prev = g; + c_prev = c; } // printf("done! lines: %d, width, %d\n", lines, pen_x_next); -- cgit v1.2.3 From 4300050e20a7fa5c06a990c1f7df3792b7fed656 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 14:13:53 +1000 Subject: Cleanup: rename kerning table to ascii_table It wasn't obvious this was only for ASCII characters. --- source/blender/blenfont/intern/blf_font.c | 2 +- source/blender/blenfont/intern/blf_glyph.c | 4 ++-- source/blender/blenfont/intern/blf_internal_types.h | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 512e2babf74..d9396bd0f90 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -372,7 +372,7 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, if (g_prev != NULL) { if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - *pen_x_p += font->kerning_cache->table[c][c_prev]; + *pen_x_p += font->kerning_cache->ascii_table[c][c_prev]; } else { FT_Vector delta; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 35938a7d5c3..a2571860c94 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -95,10 +95,10 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) .y = 0, }; if (g && g_prev && FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) { - kc->table[i][j] = (int)delta.x >> 6; + kc->ascii_table[i][j] = (int)delta.x >> 6; } else { - kc->table[i][j] = 0; + kc->ascii_table[i][j] = 0; } } } diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 6bcacc62a30..ece9a5ffae4 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -55,9 +55,11 @@ typedef struct KerningCacheBLF { /* kerning mode. */ FT_UInt mode; - /* only cache a ascii glyph pairs. Only store the x - * offset we are interested in, instead of the full FT_Vector. */ - int table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]; + /** + * Cache a ascii glyph pairs. Only store the x offset we are interested in, + * instead of the full #FT_Vector since it's not used for drawing at the moment. + */ + int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]; } KerningCacheBLF; typedef struct GlyphCacheBLF { -- cgit v1.2.3 From c0016a8581f3124d34dc8cf0a2a5c3374e72356a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 14:28:10 +1000 Subject: BLF: avoid unnecessary lookups in blf_kerning_cache_new blf_kerning_cache_new was performing many unnecessary hash lookups, calling blf_glyph_search 32768 times. Use a lookup table to reduce this to the number of ASCII characters (128 calls). --- source/blender/blenfont/intern/blf_glyph.c | 44 ++++++++++++++++-------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index a2571860c94..c5abc5982e8 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -72,34 +72,36 @@ KerningCacheBLF *blf_kerning_cache_find(FontBLF *font) /* Create a new glyph cache for the current kerning mode. */ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) { - KerningCacheBLF *kc; - - kc = (KerningCacheBLF *)MEM_callocN(sizeof(KerningCacheBLF), "blf_kerning_cache_new"); + KerningCacheBLF *kc = MEM_mallocN(sizeof(KerningCacheBLF), __func__); kc->next = NULL; kc->prev = NULL; kc->mode = font->kerning_mode; - unsigned int i, j; - for (i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { - for (j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { - GlyphBLF *g = blf_glyph_search(gc, i); - if (!g) { - FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); - g = blf_glyph_add(font, gc, glyph_index, i); + GlyphBLF *g_table[KERNING_CACHE_TABLE_SIZE]; + for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { + GlyphBLF *g = blf_glyph_search(gc, i); + if (UNLIKELY(g == NULL)) { + FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); + g = blf_glyph_add(font, gc, glyph_index, i); + } + g_table[i] = g; + } + + memset(kc->ascii_table, 0, sizeof(kc->ascii_table)); + for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { + GlyphBLF *g = g_table[i]; + if (g == NULL) { + continue; + } + for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { + GlyphBLF *g_prev = g_table[j]; + if (g_prev == NULL) { + continue; } - /* Can fail on certain fonts */ - GlyphBLF *g_prev = blf_glyph_search(gc, j); - - FT_Vector delta = { - .x = 0, - .y = 0, - }; - if (g && g_prev && FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) { + FT_Vector delta; + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) { kc->ascii_table[i][j] = (int)delta.x >> 6; } - else { - kc->ascii_table[i][j] = 0; - } } } -- cgit v1.2.3 From c48a01a88add5247f08de6f8af8d223ebc4e28c9 Mon Sep 17 00:00:00 2001 From: Himanshi Kalra Date: Mon, 16 Aug 2021 12:17:30 +0530 Subject: Add cutom data color property for mesh comparison Add color data type comparison for meshes, adding it as part of comparing meshes with geometry nodes applied. Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D12192 --- source/blender/blenkernel/intern/mesh.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index b32d58de1e2..b1292a1c94d 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -638,6 +638,19 @@ static int customdata_compare( } break; } + case CD_PROP_COLOR: { + const MPropCol *l1_data = l1->data; + const MPropCol *l2_data = l2->data; + + for (int i = 0; i < total_length; i++) { + for (int j = 0; j < 4; j++) { + if (fabsf(l1_data[i].color[j] - l2_data[i].color[j]) > thresh) { + return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; + } + } + } + break; + } default: { break; } -- cgit v1.2.3 From ddecd7aaca880586c2762c5a85d90ee8b44cd0a1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 18:06:10 +1000 Subject: Cleanup: shadow variable warning --- source/blender/blenkernel/intern/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index b1292a1c94d..e99670fc488 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -643,7 +643,7 @@ static int customdata_compare( const MPropCol *l2_data = l2->data; for (int i = 0; i < total_length; i++) { - for (int j = 0; j < 4; j++) { + for (j = 0; j < 4; j++) { if (fabsf(l1_data[i].color[j] - l2_data[i].color[j]) > thresh) { return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; } -- cgit v1.2.3 From fecec1644ce54ea386eaeed5ca6748d4a7b2737b Mon Sep 17 00:00:00 2001 From: Eitan Date: Mon, 16 Aug 2021 14:25:10 +0530 Subject: Geometry Nodes: Add UV Smooth, Boundary Smooth options to subdivision node Replaces the boolean option with enum menus for consistency with the subdivision modifier (rB66151b5de3ff,rB3d3b6d94e6e). Adds all UV interpolation options. Original patch by Eitan. Updated by Himanshi Kalra . {F9883204} Reviewed By: HooglyBoogly Differential Revision: https://developer.blender.org/D10417 --- source/blender/makesdna/DNA_node_types.h | 7 ++ source/blender/makesrna/RNA_enum_types.h | 2 + source/blender/makesrna/intern/rna_modifier.c | 85 ++++++++++------------ source/blender/makesrna/intern/rna_nodetree.c | 20 +++++ source/blender/nodes/NOD_static_types.h | 2 +- .../geometry/nodes/node_geo_subdivision_surface.cc | 43 +++++++++-- 6 files changed, 106 insertions(+), 53 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index ad7722d3ed0..fd794ed1b21 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1328,6 +1328,13 @@ typedef struct NodeAttributeConvert { int8_t domain; } NodeAttributeConvert; +typedef struct NodeGeometrySubdivisionSurface { + /* eSubsurfUVSmooth. */ + uint8_t uv_smooth; + /* eSubsurfBoundarySmooth. */ + uint8_t boundary_smooth; +} NodeGeometrySubdivisionSurface; + typedef struct NodeGeometryMeshCircle { /* GeometryNodeMeshCircleFillType. */ uint8_t fill_type; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index d544083a749..7e3f279b251 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -245,6 +245,8 @@ extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bo extern const EnumPropertyItem rna_enum_collection_color_items[]; +extern const EnumPropertyItem rna_enum_subdivision_uv_smooth_items[]; +extern const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[]; /** * For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64 * bit integers. So can't use the regular #EnumPropertyItem. Would be nice if RNA supported this diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index b424a575094..486d8d13564 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -595,6 +595,44 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_subdivision_uv_smooth_items[] = { + {SUBSURF_UV_SMOOTH_NONE, "NONE", 0, "None", "UVs are not smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, + "PRESERVE_CORNERS", + 0, + "Keep Corners", + "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, + "PRESERVE_CORNERS_AND_JUNCTIONS", + 0, + "Keep Corners, Junctions", + "UVs are smoothed, corners on discontinuous boundary and " + "junctions of 3 or more regions are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, + "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", + 0, + "Keep Corners, Junctions, Concave", + "UVs are smoothed, corners on discontinuous boundary, " + "junctions of 3 or more regions and darts and concave corners are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, + "PRESERVE_BOUNDARIES", + 0, + "Keep Boundaries", + "UVs are smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, + {0, NULL, 0, NULL, NULL}, +}; + +const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[] = { + {SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS, + "PRESERVE_CORNERS", + 0, + "Keep Corners", + "Smooth boundaries, but corners are kept sharp"}, + {SUBSURF_BOUNDARY_SMOOTH_ALL, "ALL", 0, "All", "Smooth boundaries, including corners"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DNA_curve_types.h" # include "DNA_fluid_types.h" @@ -1631,55 +1669,12 @@ static IDProperty **rna_NodesModifier_properties(PointerRNA *ptr) static void rna_def_property_subdivision_common(StructRNA *srna) { - static const EnumPropertyItem prop_uv_smooth_items[] = { - {SUBSURF_UV_SMOOTH_NONE, - "NONE", - 0, - "None", - "UVs are not smoothed, boundaries are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, - "PRESERVE_CORNERS", - 0, - "Keep Corners", - "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, - "PRESERVE_CORNERS_AND_JUNCTIONS", - 0, - "Keep Corners, Junctions", - "UVs are smoothed, corners on discontinuous boundary and " - "junctions of 3 or more regions are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, - "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", - 0, - "Keep Corners, Junctions, Concave", - "UVs are smoothed, corners on discontinuous boundary, " - "junctions of 3 or more regions and darts and concave corners are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, - "PRESERVE_BOUNDARIES", - 0, - "Keep Boundaries", - "UVs are smoothed, boundaries are kept sharp"}, - {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem prop_boundary_smooth_items[] = { - {SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS, - "PRESERVE_CORNERS", - 0, - "Keep Corners", - "Smooth boundaries, but corners are kept sharp"}, - {SUBSURF_BOUNDARY_SMOOTH_ALL, "ALL", 0, "All", "Smooth boundaries, including corners"}, - {0, NULL, 0, NULL, NULL}, - }; - PropertyRNA *prop; - RNA_define_lib_overridable(true); prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_smooth"); - RNA_def_property_enum_items(prop, prop_uv_smooth_items); + RNA_def_property_enum_items(prop, rna_enum_subdivision_uv_smooth_items); RNA_def_property_ui_text(prop, "UV Smooth", "Controls how smoothing is applied to UVs"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); @@ -1693,7 +1688,7 @@ static void rna_def_property_subdivision_common(StructRNA *srna) prop = RNA_def_property(srna, "boundary_smooth", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "boundary_smooth"); - RNA_def_property_enum_items(prop, prop_boundary_smooth_items); + RNA_def_property_enum_items(prop, rna_enum_subdivision_boundary_smooth_items); RNA_def_property_ui_text(prop, "Boundary Smooth", "Controls how open boundaries are smoothed"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b360d3b6672..7d5fffcc6c9 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -9095,6 +9095,26 @@ static void def_geo_triangulate(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_subdivision_surface(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeGeometrySubdivisionSurface", "storage"); + prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "uv_smooth"); + RNA_def_property_enum_items(prop, rna_enum_subdivision_uv_smooth_items); + RNA_def_property_enum_default(prop, SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES); + RNA_def_property_ui_text(prop, "UV Smooth", "Controls how smoothing is applied to UVs"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "boundary_smooth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "boundary_smooth"); + RNA_def_property_enum_items(prop, rna_enum_subdivision_boundary_smooth_items); + RNA_def_property_enum_default(prop, SUBSURF_BOUNDARY_SMOOTH_ALL); + RNA_def_property_ui_text(prop, "Boundary Smooth", "Controls how open boundaries are smoothed"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_geo_attribute_randomize(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 3852819746e..4da8648173d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -337,7 +337,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POIN DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "") DefNode(GeometryNode, GEO_NODE_SELECT_BY_MATERIAL, 0, "SELECT_BY_MATERIAL", SelectByMaterial, "Select by Material", "") DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") +DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index a2c10af9c4d..7882cd04845 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -20,15 +20,13 @@ #include "UI_interface.h" #include "UI_resources.h" - +#include "DNA_modifier_types.h" #include "node_geometry_util.hh" static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, {SOCK_BOOLEAN, N_("Use Creases")}, - {SOCK_BOOLEAN, N_("Boundary Smooth"), true}, - {SOCK_BOOLEAN, N_("Smooth UVs")}, {-1, ""}, }; @@ -37,6 +35,29 @@ static bNodeSocketTemplate geo_node_subdivision_surface_out[] = { {-1, ""}, }; +static void geo_node_subdivision_surface_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ +#ifndef WITH_OPENSUBDIV + uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); +#else + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "uv_smooth", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "boundary_smooth", 0, nullptr, ICON_NONE); +#endif +} + +static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( + sizeof(NodeGeometrySubdivisionSurface), __func__); + data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; + data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL; + node->storage = data; +} + namespace blender::nodes { static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) { @@ -53,6 +74,9 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, TIP_("Disabled, Blender was compiled without OpenSubdiv")); #else + const NodeGeometrySubdivisionSurface &storage = *(const NodeGeometrySubdivisionSurface *)params.node().storage; + const int uv_smooth = storage.uv_smooth; + const int boundary_smooth = storage.boundary_smooth; const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 30); /* Only process subdivision if level is greater than 0. */ @@ -62,8 +86,6 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) } const bool use_crease = params.extract_input("Use Creases"); - const bool boundary_smooth = params.extract_input("Boundary Smooth"); - const bool smooth_uvs = params.extract_input("Smooth UVs"); const Mesh *mesh_in = geometry_set.get_mesh_for_read(); /* Initialize mesh settings. */ @@ -79,9 +101,9 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) subdiv_settings.level = subdiv_level; subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( - !boundary_smooth); + boundary_smooth); subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( - smooth_uvs); + uv_smooth); /* Apply subdivision to mesh. */ Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in); @@ -117,5 +139,12 @@ void register_node_type_geo_subdivision_surface() node_type_socket_templates( &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; + ntype.draw_buttons = geo_node_subdivision_surface_layout; + node_type_init(&ntype, geo_node_subdivision_surface_init); + node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); + node_type_storage( + &ntype, "NodeGeometrySubdivisionSurface", node_free_standard_storage, node_copy_standard_storage); + node_type_socket_templates( + &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); nodeRegisterType(&ntype); } -- cgit v1.2.3 From 08af3e6e926bf1d448bfdae8ffa2593d0850e016 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 5 Jul 2021 14:16:02 +0200 Subject: VSE: Flush audio encode after finishing video export We didn't flush audio after encoding finished which lead to audio packets being lost. In addition to this the audio timestamps were wrong because we incremented the current audio time before using it. Reviewed By: Richard Antalik Differential Revision: http://developer.blender.org/D11916 --- source/blender/blenkernel/intern/writeffmpeg.c | 37 +++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 32057709c38..9f3f50febe8 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -149,7 +149,6 @@ static int write_audio_frame(FFMpegContext *context) AUD_Device_read( context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples); - context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate; frame = av_frame_alloc(); frame->pts = context->audio_time / av_q2d(c->time_base); @@ -184,7 +183,7 @@ static int write_audio_frame(FFMpegContext *context) context->audio_input_samples * c->channels * context->audio_sample_size, 1); - int success = 0; + int success = 1; int ret = avcodec_send_frame(c, frame); if (ret < 0) { @@ -369,7 +368,7 @@ static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, R return success; } -/* read and encode a frame of audio from the buffer */ +/* read and encode a frame of video from the buffer */ static AVFrame *generate_video_frame(FFMpegContext *context, const uint8_t *pixels) { AVCodecParameters *codec = context->video_stream->codecpar; @@ -1226,9 +1225,8 @@ fail: * parameter. *

*/ -static void flush_ffmpeg(FFMpegContext *context) +static void flush_ffmpeg(AVCodecContext *c, AVStream *stream, AVFormatContext *outfile) { - AVCodecContext *c = context->video_codec; AVPacket *packet = av_packet_alloc(); avcodec_send_frame(c, NULL); @@ -1247,13 +1245,13 @@ static void flush_ffmpeg(FFMpegContext *context) break; } - packet->stream_index = context->video_stream->index; - av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base); + packet->stream_index = stream->index; + av_packet_rescale_ts(packet, c->time_base, stream->time_base); # ifdef FFMPEG_USE_DURATION_WORKAROUND - my_guess_pkt_duration(context->outfile, context->video_stream, packet); + my_guess_pkt_duration(context->outfile, stream, packet); # endif - int write_ret = av_interleaved_write_frame(context->outfile, packet); + int write_ret = av_interleaved_write_frame(outfile, packet); if (write_ret != 0) { fprintf(stderr, "Error writing delayed frame: %s\n", av_err2str(write_ret)); break; @@ -1396,12 +1394,13 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit); # ifdef WITH_AUDASPACE static void write_audio_frames(FFMpegContext *context, double to_pts) { - int finished = 0; + AVCodecContext *c = context->audio_codec; - while (context->audio_stream && !finished) { - if ((context->audio_time >= to_pts) || (write_audio_frame(context))) { - finished = 1; + while (context->audio_stream) { + if ((context->audio_time >= to_pts) || !write_audio_frame(context)) { + break; } + context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate; } } # endif @@ -1422,9 +1421,6 @@ int BKE_ffmpeg_append(void *context_v, PRINT("Writing frame %i, render width=%d, render height=%d\n", frame, rectx, recty); - /* why is this done before writing the video frame and again at end_ffmpeg? */ - // write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base)); - if (context->video_stream) { avframe = generate_video_frame(context, (unsigned char *)pixels); success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports)); @@ -1461,8 +1457,13 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) # endif if (context->video_stream) { - PRINT("Flushing delayed frames...\n"); - flush_ffmpeg(context); + PRINT("Flushing delayed video frames...\n"); + flush_ffmpeg(context->video_codec, context->video_stream, context->outfile); + } + + if (context->audio_stream) { + PRINT("Flushing delayed audio frames...\n"); + flush_ffmpeg(context->audio_codec, context->audio_stream, context->outfile); } if (context->outfile) { -- cgit v1.2.3 From e314260fa778b5d0874cadab1f70f91bddd18434 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Fri, 9 Jul 2021 15:06:06 +0200 Subject: VSE: Fix "off by one" error when encoding audio Before we didn't encode the audio up until the current frame. This lead to us not encoding the last video frame of audio. Reviewed By: Richard Antalik Differential Revision: http://developer.blender.org/D11918 --- source/blender/blenkernel/intern/writeffmpeg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 9f3f50febe8..323da7473b5 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1435,8 +1435,9 @@ int BKE_ffmpeg_append(void *context_v, } # ifdef WITH_AUDASPACE - write_audio_frames(context, - (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base)); + /* Add +1 frame because we want to encode audio up until the next video frame. */ + write_audio_frames( + context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base)); # endif return success; } -- cgit v1.2.3 From 43ad345caa0ac156f585eab55e335dfca2465ce4 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 12 Jul 2021 15:38:25 +0200 Subject: VSE: Fix memory leak when adding bad image/movie strips If the add strip operator errored out, we wouldn't free custom data allocated Reviewed By: Richard Antalik Differential Revision: http://developer.blender.org/D11919 --- source/blender/editors/space_sequencer/sequencer_add.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 265a52ed1a6..47495eaa57a 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -707,13 +707,13 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) } else { if (!sequencer_add_movie_single_strip(C, op, &load_data)) { + sequencer_add_cancel(C, op); return OPERATOR_CANCELLED; } } - if (op->customdata) { - MEM_freeN(op->customdata); - } + /* Free custom data. */ + sequencer_add_cancel(C, op); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -1040,6 +1040,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) load_data.image.len = sequencer_add_image_strip_calculate_length( op, load_data.start_frame, &minframe, &numdigits); if (load_data.image.len == 0) { + sequencer_add_cancel(C, op); return OPERATOR_CANCELLED; } @@ -1062,9 +1063,8 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - if (op->customdata) { - MEM_freeN(op->customdata); - } + /* Free custom data. */ + sequencer_add_cancel(C, op); return OPERATOR_FINISHED; } -- cgit v1.2.3 From a01cf90fd8ad978d8b6c7fd2ece64872c940f3a1 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 12 Jul 2021 16:00:43 +0200 Subject: VSE: Fix video strip duration calculation The video duration was not read correctly from the video file. It would use the global duration of the file which does in some cases not line up with the actual duration of the video stream. Now we take the video stream duration and start time into account when calculating the strip duration. Reviewed By: Richard Antalik Differential Revision: http://developer.blender.org/D11920 --- source/blender/imbuf/intern/anim_movie.c | 46 +++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 47514308ae4..c08df2889de 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -616,10 +616,50 @@ static int startffmpeg(struct anim *anim) } } } - /* Fall back to the container. */ + /* Fall back to manually estimating the video stream duration. + * This is because the video stream duration can be shorter than the pFormatCtx->duration. + */ if (anim->duration_in_frames == 0) { - anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + - 0.5f); + double pts_time_base = av_q2d(video_stream->time_base); + double stream_dur; + + if (video_stream->duration != AV_NOPTS_VALUE) { + stream_dur = video_stream->duration * pts_time_base; + } + else { + double video_start = 0; + double audio_start = 0; + + if (video_stream->start_time != AV_NOPTS_VALUE) { + video_start = video_stream->start_time * pts_time_base; + } + + /* Find audio stream to guess the duration of the video. + * Sometimes the audio AND the video stream have a start offset. + * The difference between these is the offset we want to use to + * calculate the video duration. + */ + for (i = 0; i < pFormatCtx->nb_streams; i++) { + if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + AVStream *audio_stream = pFormatCtx->streams[i]; + if (audio_stream->start_time != AV_NOPTS_VALUE) { + audio_start = audio_stream->start_time * av_q2d(audio_stream->time_base); + } + break; + } + } + + if (video_start > audio_start) { + stream_dur = (double)pFormatCtx->duration / AV_TIME_BASE - (video_start - audio_start); + } + else { + /* The video stream starts before or at the same time as the audio stream! + * We have to assume that the video stream is as long as the full pFormatCtx->duration. + */ + stream_dur = (double)pFormatCtx->duration / AV_TIME_BASE; + } + } + anim->duration_in_frames = (int)(stream_dur * av_q2d(frame_rate) + 0.5f); } frs_num = frame_rate.num; -- cgit v1.2.3 From 6df81ddb84c60876ac3ebd87d1d134109f34eabd Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 12 Jul 2021 19:13:15 +0200 Subject: VSE: Fix seeking issues. The seek pts was not correctly calculated. In addition to that we were not seeking in the video pts time base. Reviewed By: Richard Antalik Differential Revision: http://developer.blender.org/D11921 --- source/blender/imbuf/intern/anim_movie.c | 87 +++++++++++++++----------------- source/blender/imbuf/intern/indexer.c | 2 +- 2 files changed, 42 insertions(+), 47 deletions(-) (limited to 'source/blender') diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index c08df2889de..fd96110b59e 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1059,33 +1059,21 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx) return false; } -static int64_t ffmpeg_get_seek_pos(struct anim *anim, int position) +static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); - int64_t st_time = anim->pFormatCtx->start_time; - int64_t pos = (int64_t)(position)*AV_TIME_BASE; - /* Step back half a time base position to make sure that we get the requested - * frame and not the one after it. + AVRational frame_rate = v_st->r_frame_rate; + AVRational time_base = v_st->time_base; + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); + /* Step back half a frame position to make sure that we get the requested + * frame and not the one after it. This is a workaround as ffmpeg will + * sometimes not seek to a frame after the requested pts even if + * AVSEEK_FLAG_BACKWARD is specified. */ - pos -= (AV_TIME_BASE / 2); - pos /= frame_rate; + int64_t pts = pts_to_search - (steps_per_frame / 2); - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n", - pos, - (st_time != AV_NOPTS_VALUE) ? st_time : 0); - - if (pos < 0) { - pos = 0; - } - - if (st_time != AV_NOPTS_VALUE) { - pos += st_time; - } - - return pos; + return pts; } /* This gives us an estimate of which pts our requested frame will have. @@ -1102,17 +1090,18 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim, pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index); } else { - int64_t st_time = anim->pFormatCtx->start_time; AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL); + int64_t start_pts = v_st->start_time; + AVRational frame_rate = v_st->r_frame_rate; AVRational time_base = v_st->time_base; - int64_t steps_per_frame = (frame_rate.den * time_base.den) / (frame_rate.num * time_base.num); - pts_to_search = position * steps_per_frame; + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); + + pts_to_search = round(position * steps_per_frame); - if (st_time != AV_NOPTS_VALUE && st_time != 0) { - int64_t start_frame = (double)st_time / AV_TIME_BASE * av_q2d(frame_rate); - pts_to_search += start_frame * steps_per_frame; + if (start_pts != AV_NOPTS_VALUE) { + pts_to_search += start_pts; } } return pts_to_search; @@ -1196,23 +1185,29 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea * decoded will be read. See https://trac.ffmpeg.org/ticket/1607 and * https://developer.blender.org/T86944. */ static int ffmpeg_generic_seek_workaround(struct anim *anim, - int64_t *requested_pos, + int64_t *requested_pts, int64_t pts_to_search) { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); - int64_t current_pos = *requested_pos; + AVRational frame_rate = v_st->r_frame_rate; + AVRational time_base = v_st->time_base; + + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); + + int64_t current_pts = *requested_pts; int64_t offset = 0; int64_t cur_pts, prev_pts = -1; /* Step backward frame by frame until we find the key frame we are looking for. */ - while (current_pos != 0) { - current_pos = *requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate); - current_pos = max_ii(current_pos, 0); + while (current_pts != 0) { + current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame); + current_pts = max_ii(current_pts, 0); /* Seek to timestamp. */ - if (av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD) < 0) { + if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < + 0) { break; } @@ -1249,10 +1244,10 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, offset++; } - *requested_pos = current_pos; + *requested_pts = current_pts; /* Re-seek to timestamp that gave I-frame, so it can be read by decode function. */ - return av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD); + return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD); } /* Seek to last necessary key frame. */ @@ -1300,13 +1295,13 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, else { /* We have to manually seek with ffmpeg to get to the key frame we want to start decoding from. */ - pos = ffmpeg_get_seek_pos(anim, position); + pos = ffmpeg_get_seek_pts(anim, pts_to_search); av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos); AVFormatContext *format_ctx = anim->pFormatCtx; if (format_ctx->iformat->read_seek2 || format_ctx->iformat->read_seek) { - ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); + ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD); } else { ret = ffmpeg_generic_seek_workaround(anim, &pos, pts_to_search); @@ -1351,7 +1346,7 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, anim->cur_key_frame_pts = gop_pts; /* Seek back so we are at the correct position after we decoded a frame. */ - av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); + av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD); } } @@ -1391,18 +1386,18 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ struct anim_index *tc_index = IMB_anim_open_index(anim, tc); int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position); AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + double frame_rate = av_q2d(v_st->r_frame_rate); double pts_time_base = av_q2d(v_st->time_base); - int64_t st_time = anim->pFormatCtx->start_time; + int64_t start_pts = v_st->start_time; av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64 + "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64 ")\n", (int64_t)pts_to_search, pts_time_base, frame_rate, - st_time); + start_pts); if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) { av_log(anim->pFormatCtx, diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 27195b294d6..bbb0f3b5b22 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -1022,7 +1022,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, stream_size = avio_size(context->iFormatCtx->pb); - context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL)); + context->frame_rate = av_q2d(context->iStream->r_frame_rate); context->pts_time_base = av_q2d(context->iStream->time_base); while (av_read_frame(context->iFormatCtx, next_packet) >= 0) { -- cgit v1.2.3 From ded68fb10275c9f9a66e7019171b83cab0e9485d Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 6 Jul 2021 19:48:06 +0200 Subject: VSE: Fix audaspace not reading ffmpeg files with start offset correctly The duration and start time for audio strips were not correctly read in audaspace. Some video files have a "lead in" section of audio that plays before the video starts playing back. Before this patch, we would play this lead in audio at the same time as the video started and thus the audio would not be in sync anymore. Now the lead in audio is cut off and the duration should be correctly calculated with this in mind. If the audio starts after the video, the audio strip is shifted to account for this, but it will also lead to cut off audio which might not be wanted. However we don't have a simple way to solve this at this point. Differential Revision: http://developer.blender.org/D11917 --- source/blender/blenkernel/BKE_sound.h | 9 ++++- source/blender/blenkernel/intern/sound.c | 12 +++--- .../editors/space_sequencer/sequencer_add.c | 16 +++++--- .../editors/space_sequencer/sequencer_draw.c | 10 +++-- source/blender/imbuf/IMB_imbuf.h | 5 +++ source/blender/imbuf/intern/IMB_anim.h | 1 + source/blender/imbuf/intern/anim_movie.c | 27 ++++++++++--- source/blender/makesdna/DNA_sound_types.h | 1 + source/blender/makesrna/intern/rna_sequencer_api.c | 5 ++- source/blender/sequencer/SEQ_add.h | 6 ++- source/blender/sequencer/intern/sound.c | 7 +++- source/blender/sequencer/intern/strip_add.c | 46 ++++++++++++++++++---- source/blender/sequencer/intern/strip_time.c | 4 +- 13 files changed, 113 insertions(+), 36 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 57ce33a239f..4b257b3b8ab 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -97,6 +97,7 @@ typedef struct SoundInfo { eSoundChannels channels; } specs; float length; + double start_offset; } SoundInfo; /* Get information about given sound. Returns truth on success., false if sound can not be loaded @@ -139,8 +140,12 @@ void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle); void BKE_sound_mute_scene_sound(void *handle, char mute); -void BKE_sound_move_scene_sound( - struct Scene *scene, void *handle, int startframe, int endframe, int frameskip); +void BKE_sound_move_scene_sound(struct Scene *scene, + void *handle, + int startframe, + int endframe, + int frameskip, + double audio_offset); void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence); void BKE_sound_update_scene_sound(void *handle, struct bSound *sound); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index fcb992e1535..9d287377545 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -709,7 +709,7 @@ void *BKE_sound_scene_add_scene_sound( sequence->scene->sound_scene, startframe / fps, endframe / fps, - frameskip / fps); + frameskip / fps + sequence->sound->offset_time); } return NULL; } @@ -737,7 +737,7 @@ void *BKE_sound_add_scene_sound( sequence->sound->playback_handle, startframe / fps, endframe / fps, - frameskip / fps); + frameskip / fps + sequence->sound->offset_time); AUD_SequenceEntry_setMuted(handle, (sequence->flag & SEQ_MUTE) != 0); AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, CFRA, &sequence->volume, 0); AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, CFRA, &sequence->pitch, 0); @@ -765,11 +765,11 @@ void BKE_sound_mute_scene_sound(void *handle, char mute) } void BKE_sound_move_scene_sound( - Scene *scene, void *handle, int startframe, int endframe, int frameskip) + Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset) { sound_verify_evaluated_id(&scene->id); const double fps = FPS; - AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps); + AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps + audio_offset); } void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence) @@ -780,7 +780,8 @@ void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence) sequence->scene_sound, sequence->startdisp, sequence->enddisp, - sequence->startofs + sequence->anim_startofs); + sequence->startofs + sequence->anim_startofs, + sequence->sound->offset_time); } } @@ -1213,6 +1214,7 @@ static bool sound_info_from_playback_handle(void *playback_handle, SoundInfo *so AUD_SoundInfo info = AUD_getInfo(playback_handle); sound_info->specs.channels = (eSoundChannels)info.specs.channels; sound_info->length = info.length; + sound_info->start_offset = info.start_offset; return true; } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 47495eaa57a..ff8cbdb1a59 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -643,15 +643,17 @@ static void sequencer_add_movie_multiple_strips(bContext *C, BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); Sequence *seq_movie = NULL; Sequence *seq_sound = NULL; + double video_start_offset; + load_data->channel++; - seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); + seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset); load_data->channel--; if (seq_movie == NULL) { BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); } else { if (RNA_boolean_get(op->ptr, "sound")) { - seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset); } load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; seq_load_apply_generic_options(C, op, seq_sound); @@ -670,8 +672,10 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa Sequence *seq_movie = NULL; Sequence *seq_sound = NULL; + double video_start_offset; + load_data->channel++; - seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); + seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset); load_data->channel--; if (seq_movie == NULL) { @@ -679,7 +683,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa return false; } if (RNA_boolean_get(op->ptr, "sound")) { - seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset); } seq_load_apply_generic_options(C, op, seq_sound); seq_load_apply_generic_options(C, op, seq_movie); @@ -822,7 +826,7 @@ static void sequencer_add_sound_multiple_strips(bContext *C, RNA_string_get(&itemptr, "name", file_only); BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only); BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); - Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, 0.0f); if (seq == NULL) { BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); } @@ -840,7 +844,7 @@ static bool sequencer_add_sound_single_strip(bContext *C, wmOperator *op, SeqLoa Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, true); - Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, 0.0f); if (seq == NULL) { BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); return false; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 0472e1264ce..e49a88c88d2 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -284,10 +284,12 @@ static void draw_seq_waveform_overlay(View2D *v2d, return; } - startsample = floor((seq->startofs + seq->anim_startofs) / FPS * - SOUND_WAVE_SAMPLES_PER_SECOND); - endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS * - SOUND_WAVE_SAMPLES_PER_SECOND); + startsample = (seq->startofs + seq->anim_startofs) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND; + startsample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND; + + endsample = (seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND; + endsample += startsample; + samplestep = (endsample - startsample) * stepsize / (x2 - x1); length = min_ii( diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index d527aca184c..4ad7aa98484 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -366,6 +366,11 @@ void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop */ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc); +/** + * Return the encoded start offset (in seconds) of the given \a anim. + */ +double IMD_anim_get_offset(struct anim *anim); + /** * Return the fps contained in movie files (function rval is false, * and frs_sec and frs_sec_base untouched if none available!) diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index cfeffcca0ea..c4e2ad9da7f 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -91,6 +91,7 @@ struct anim { int duration_in_frames; int frs_sec; double frs_sec_base; + double start_offset; int x, y; /* for number */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index fd96110b59e..2998c4781b6 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -425,6 +425,7 @@ static int startavi(struct anim *anim) } anim->duration_in_frames = anim->avi->header->TotalFrames; + anim->start_offset = 0.0f; anim->params = NULL; anim->x = anim->avi->header->Width; @@ -597,6 +598,13 @@ static int startffmpeg(struct anim *anim) return -1; } + double video_start = 0; + double pts_time_base = av_q2d(video_stream->time_base); + + if (video_stream->start_time != AV_NOPTS_VALUE) { + video_start = video_stream->start_time * pts_time_base; + } + frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL); anim->duration_in_frames = 0; @@ -620,20 +628,14 @@ static int startffmpeg(struct anim *anim) * This is because the video stream duration can be shorter than the pFormatCtx->duration. */ if (anim->duration_in_frames == 0) { - double pts_time_base = av_q2d(video_stream->time_base); double stream_dur; if (video_stream->duration != AV_NOPTS_VALUE) { stream_dur = video_stream->duration * pts_time_base; } else { - double video_start = 0; double audio_start = 0; - if (video_stream->start_time != AV_NOPTS_VALUE) { - video_start = video_stream->start_time * pts_time_base; - } - /* Find audio stream to guess the duration of the video. * Sometimes the audio AND the video stream have a start offset. * The difference between these is the offset we want to use to @@ -662,6 +664,11 @@ static int startffmpeg(struct anim *anim) anim->duration_in_frames = (int)(stream_dur * av_q2d(frame_rate) + 0.5f); } + double ctx_start = 0; + if (pFormatCtx->start_time != AV_NOPTS_VALUE) { + ctx_start = (double)pFormatCtx->start_time / AV_TIME_BASE; + } + frs_num = frame_rate.num; frs_den = frame_rate.den; @@ -674,6 +681,9 @@ static int startffmpeg(struct anim *anim) anim->frs_sec = frs_num; anim->frs_sec_base = frs_den; + /* Save the relative start time for the video. IE the start time in relation to where playback + * starts. */ + anim->start_offset = video_start - ctx_start; anim->params = 0; @@ -1672,6 +1682,11 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) return IMB_indexer_get_duration(idx); } +double IMD_anim_get_offset(struct anim *anim) +{ + return anim->start_offset; +} + bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base) { double frs_sec_base_double; diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index b2bb50c56a2..e6394f0a56a 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -67,6 +67,7 @@ typedef struct bSound { /** Runtime only, always reset in readfile. */ short tags; char _pad[4]; + double offset_time; /* Unused currently. */ // int type; diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 4895ab11618..264ccccd350 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -310,7 +310,8 @@ static Sequence *rna_Sequences_new_movie(ID *id, SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); load_data.fit_method = fit_method; load_data.allow_invalid_file = true; - Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data); + double video_start_offset; + Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data, &video_start_offset); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -359,7 +360,7 @@ static Sequence *rna_Sequences_new_sound(ID *id, SeqLoadData load_data; SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); load_data.allow_invalid_file = true; - Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data); + Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data, 0.0f); if (seq == NULL) { BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file"); diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h index 2941eb6f4c0..4025f1a4a04 100644 --- a/source/blender/sequencer/SEQ_add.h +++ b/source/blender/sequencer/SEQ_add.h @@ -79,14 +79,16 @@ struct Sequence *SEQ_add_image_strip(struct Main *bmain, struct Sequence *SEQ_add_sound_strip(struct Main *bmain, struct Scene *scene, struct ListBase *seqbase, - struct SeqLoadData *load_data); + struct SeqLoadData *load_data, + const double audio_offset); struct Sequence *SEQ_add_meta_strip(struct Scene *scene, struct ListBase *seqbase, struct SeqLoadData *load_data); struct Sequence *SEQ_add_movie_strip(struct Main *bmain, struct Scene *scene, struct ListBase *seqbase, - struct SeqLoadData *load_data); + struct SeqLoadData *load_data, + double *r_video_start_offset); struct Sequence *SEQ_add_scene_strip(struct Scene *scene, struct ListBase *seqbase, struct SeqLoadData *load_data); diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c index 1054dbeeba6..c53aacddcfe 100644 --- a/source/blender/sequencer/intern/sound.c +++ b/source/blender/sequencer/intern/sound.c @@ -111,7 +111,12 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq) /* We have to take into account start frame of the sequence's scene! */ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra; - BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs); + BKE_sound_move_scene_sound(scene, + seq->scene_sound, + seq->startdisp, + seq->enddisp, + startofs, + seq->sound->offset_time); } } else { diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index dab5593be37..cc70cc38ebb 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -382,9 +382,14 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL * \return created strip */ -Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) +Sequence *SEQ_add_sound_strip(Main *bmain, + Scene *scene, + ListBase *seqbase, + SeqLoadData *load_data, + const double audio_offset) { bSound *sound = BKE_sound_new_file(bmain, load_data->path); /* Handles relative paths. */ + sound->offset_time = audio_offset; SoundInfo info; bool sound_loaded = BKE_sound_info_get(bmain, sound, &info); @@ -398,14 +403,36 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL return NULL; } - Sequence *seq = SEQ_sequence_alloc( - seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SOUND_RAM); + /* If this sound it part of a video, then the sound might start after the video. + * In this case we need to then offset the start frame of the audio so it syncs up + * properly with the video. + */ + int start_frame_offset = info.start_offset * FPS; + double start_frame_offset_remainer = (info.start_offset * FPS - start_frame_offset) / FPS; + + if (start_frame_offset_remainer > FLT_EPSILON) { + /* We can't represent a fraction of a frame, so skip the first frame fraction of sound so we + * start on a "whole" frame. + */ + start_frame_offset++; + } + + sound->offset_time += start_frame_offset_remainer; + + Sequence *seq = SEQ_sequence_alloc(seqbase, + load_data->start_frame + start_frame_offset, + load_data->channel, + SEQ_TYPE_SOUND_RAM); seq->sound = sound; seq->scene_sound = NULL; - /* We add a very small negative offset here, because - * ceil(132.0) == 133.0, not nice with videos, see T47135. */ - seq->len = MAX2(1, (int)ceil((double)info.length * FPS - 1e-4)); + /* We round the frame duration as the audio sample lenghts usually does not + * line up with the video frames. Therefore we round this number to the + * nearsest frame as the audio track usually overshoots or undershoots the + * end frame ofthe video by a little bit. + * See T47135 for under shoot example. + */ + seq->len = MAX2(1, round((info.length - sound->offset_time) * FPS)); Strip *strip = seq->strip; /* We only need 1 element to store the filename. */ @@ -477,7 +504,11 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_ * \param load_data: SeqLoadData with information necessary to create strip * \return created strip */ -Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) +Sequence *SEQ_add_movie_strip(Main *bmain, + Scene *scene, + ListBase *seqbase, + SeqLoadData *load_data, + double *r_video_start_offset) { char path[sizeof(load_data->path)]; BLI_strncpy(path, load_data->path, sizeof(path)); @@ -552,6 +583,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); + *r_video_start_offset = IMD_anim_get_offset(anim_arr[0]); IMB_anim_load_metadata(anim_arr[0]); diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 68128690773..b73ac631693 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -34,6 +34,7 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "DNA_sound_types.h" #include "IMB_imbuf.h" #include "SEQ_iterator.h" @@ -134,7 +135,8 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene, seq->scene_sound, seq->start + startofs, seq->start + seq->len - endofs, - startofs + seq->anim_startofs); + startofs + seq->anim_startofs, + seq->sound->offset_time); } } } -- cgit v1.2.3 From 2946f72a2a1f4afc4967ceda28df4294de304b81 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Thu, 1 Jul 2021 18:51:26 +0200 Subject: VSE: Use lines to draw waveform Refactor and improve waveform drawing. Drawing now can use line strips to draw waveforms instead of only triangle strips. This makes us able to properly visualize thin waveforms as they would not be visible before. We now also draw the RMS value of the waveform. The waveform drawing is now also properly aligned to the screen pixels to avoid flickering when transforming the strip. Reviewed By: Richard Antalik Differential Revision: https://developer.blender.org/D11184 --- .../editors/space_sequencer/sequencer_draw.c | 328 ++++++++++++++++----- 1 file changed, 258 insertions(+), 70 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e49a88c88d2..888e232ce45 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -228,9 +228,93 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3]) } } +typedef struct WaveVizData { + float pos[2]; + float rms_pos; + bool clip; + bool end; +} WaveVizData; + +static int get_section_len(WaveVizData *start, WaveVizData *end) +{ + int len = 0; + while (start != end) { + len++; + if (start->end) { + return len; + } + start++; + } + return len; +} + +static void draw_waveform(WaveVizData *iter, WaveVizData *end, GPUPrimType prim_type, bool use_rms) +{ + int strip_len = get_section_len(iter, end); + if (strip_len > 1) { + GPU_blend(GPU_BLEND_ALPHA); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(prim_type, strip_len); + + while (iter != end) { + if (iter->clip) { + immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f); + } + else if (use_rms) { + immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.8f); + } + else { + immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f); + } + + if (use_rms) { + immVertex2f(pos, iter->pos[0], iter->rms_pos); + } + else { + immVertex2f(pos, iter->pos[0], iter->pos[1]); + } + + if (iter->end) { + /* End of line. */ + iter++; + strip_len = get_section_len(iter, end); + if (strip_len != 0) { + immEnd(); + immUnbindProgram(); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(prim_type, strip_len); + } + } + else { + iter++; + } + } + immEnd(); + immUnbindProgram(); + + GPU_blend(GPU_BLEND_NONE); + } +} + +static float clamp_frame_coord_to_pixel(float frame_coord, + float pixel_frac, + float frames_per_pixel) +{ + float cur_pixel = (frame_coord / frames_per_pixel); + float new_pixel = (int)(frame_coord / frames_per_pixel) + pixel_frac; + if (cur_pixel > new_pixel) { + new_pixel += 1.0f; + } + return new_pixel * frames_per_pixel; +} + /** * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. - * \param stepsize: The width of a pixel. + * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction). */ static void draw_seq_waveform_overlay(View2D *v2d, const bContext *C, @@ -241,29 +325,34 @@ static void draw_seq_waveform_overlay(View2D *v2d, float y1, float x2, float y2, - float stepsize) + float frames_per_pixel) { - /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ - int x1_offset = max_ff(v2d->cur.xmin, x1); - int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2); - if (seq->sound && ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { - int length = floor((x2_offset - x1_offset) / stepsize) + 1; - float ymid = (y1 + y2) / 2.0f; - float yscale = (y2 - y1) / 2.0f; - float samplestep; - float startsample, endsample; - float volume = seq->volume; - float value1, value2; - bSound *sound = seq->sound; - SoundWaveform *waveform; - - if (length < 2) { + /* Make sure that the start drawing position is aligned to the pixels on the screen to avoid + * flickering whem moving around the strip. + * To do this we figure out the fractional offset in pixel space by checking where the + * window starts. + * We then append this pixel offset to our strip start coordiate to ensure we are aligned to + * the screen pixel grid. */ + float pixel_frac = v2d->cur.xmin / frames_per_pixel - floor(v2d->cur.xmin / frames_per_pixel); + float x1_adj = clamp_frame_coord_to_pixel(x1, pixel_frac, frames_per_pixel); + + /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ + float x1_offset = max_ff(v2d->cur.xmin, x1_adj); + float x2_offset = min_ff(v2d->cur.xmax, x2); + + /* Calculate how long the strip that is in view is in pixels. */ + int pix_strip_len = round((x2_offset - x1_offset) / frames_per_pixel); + + if (pix_strip_len < 2) { return; } + bSound *sound = seq->sound; + BLI_spin_lock(sound->spinlock); if (!sound->waveform) { + /* Load the waveform data if it hasn't been loaded and cached already. */ if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) { /* Prevent sounds from reloading. */ sound->tags |= SOUND_TAGS_WAVEFORM_LOADING; @@ -277,89 +366,188 @@ static void draw_seq_waveform_overlay(View2D *v2d, } BLI_spin_unlock(sound->spinlock); - waveform = sound->waveform; + SoundWaveform *waveform = sound->waveform; /* Waveform could not be built. */ if (waveform->length == 0) { return; } - startsample = (seq->startofs + seq->anim_startofs) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND; - startsample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND; + /* F-curve lookup is quite expensive, so do this after precondition. */ + FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL); - endsample = (seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND; - endsample += startsample; + WaveVizData *tri_strip_arr = MEM_callocN(sizeof(*tri_strip_arr) * pix_strip_len * 2, + "tri_strip"); + WaveVizData *line_strip_arr = MEM_callocN(sizeof(*line_strip_arr) * pix_strip_len, + "line_strip"); - samplestep = (endsample - startsample) * stepsize / (x2 - x1); + WaveVizData *tri_strip_iter = tri_strip_arr; + WaveVizData *line_strip_iter = line_strip_arr; - length = min_ii( - floor((waveform->length - startsample) / samplestep - (x1_offset - x1) / stepsize), - length); + /* The y coordinate for the middle of the strip. */ + float y_mid = (y1 + y2) / 2.0f; + /* The lenght from the middle of the strip to the top/bottom. */ + float y_scale = (y2 - y1) / 2.0f; + float volume = seq->volume; - if (length < 2) { - return; - } + /* Value to keep track if the previous item to be drawn was a line strip. */ + int8_t was_line_strip = -1; /* -1 == no previous value. */ - /* F-curve lookup is quite expensive, so do this after precondition. */ - FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL); + float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS; - GPU_blend(GPU_BLEND_ALPHA); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - immBegin(GPU_PRIM_TRI_STRIP, length * 2); + /* How many samples do we have for each pixel? */ + float samples_per_pix = samples_per_frame * frames_per_pixel; - for (int i = 0; i < length; i++) { - float sampleoffset = startsample + ((x1_offset - x1) / stepsize + i) * samplestep; - int p = sampleoffset; + float strip_start_offset = seq->startofs + seq->anim_startofs; + float start_sample = 0; - value1 = waveform->data[p * 3]; - value2 = waveform->data[p * 3 + 1]; + if (strip_start_offset != 0) { + /* If start offset is not zero, we need to make sure that we pick the same start sample as if + * we simply scrolled the start of the strip offscreen. Otherwise we will get flickering when + * changing start offset as the pixel alignment will not be the same for the drawn samples. + */ + strip_start_offset = clamp_frame_coord_to_pixel( + x1 - strip_start_offset, pixel_frac, frames_per_pixel); + start_sample = fabsf(strip_start_offset - x1_adj) * samples_per_frame; + } - if (samplestep > 1.0f) { - for (int j = p + 1; (j < waveform->length) && (j < p + samplestep); j++) { - if (value1 > waveform->data[j * 3]) { - value1 = waveform->data[j * 3]; - } + start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND; + /* If we scrolled the start off-screen, then the start sample should be at the first visible + * sample. */ + start_sample += (x1_offset - x1_adj) * samples_per_frame; - if (value2 < waveform->data[j * 3 + 1]) { - value2 = waveform->data[j * 3 + 1]; - } - } + for (int i = 0; i < pix_strip_len; i++) { + float sample_offset = start_sample + i * samples_per_pix; + int p = sample_offset; + + if (p >= waveform->length) { + break; } - else if (p + 1 < waveform->length) { + + float value_min = waveform->data[p * 3]; + float value_max = waveform->data[p * 3 + 1]; + float rms = waveform->data[p * 3 + 2]; + + if (p + 1 < waveform->length) { /* Use simple linear interpolation. */ - float f = sampleoffset - p; - value1 = (1.0f - f) * value1 + f * waveform->data[p * 3 + 3]; - value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4]; + float f = sample_offset - p; + value_min = (1.0f - f) * value_min + f * waveform->data[p * 3 + 3]; + value_max = (1.0f - f) * value_max + f * waveform->data[p * 3 + 4]; + rms = (1.0f - f) * rms + f * waveform->data[p * 3 + 5]; + if (samples_per_pix > 1.0f) { + /* We need to sum up the values we skip over until the next step. */ + float next_pos = sample_offset + samples_per_pix; + int end_idx = next_pos; + + for (int j = p + 1; (j < waveform->length) && (j < end_idx); j++) { + value_min = min_ff(value_min, waveform->data[j * 3]); + value_max = max_ff(value_max, waveform->data[j * 3 + 1]); + rms = max_ff(rms, waveform->data[j * 3 + 2]); + } + } } if (fcu && !BKE_fcurve_is_empty(fcu)) { - float evaltime = x1_offset + (i * stepsize); + float evaltime = x1_offset + (i * frames_per_pixel); volume = evaluate_fcurve(fcu, evaltime); CLAMP_MIN(volume, 0.0f); } - value1 *= volume; - value2 *= volume; - if (value2 > 1 || value1 < -1) { - immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f); + value_min *= volume; + value_max *= volume; + rms *= volume; + + bool clipping = false; + + if (value_max > 1 || value_min < -1) { + clipping = true; - CLAMP_MAX(value2, 1.0f); - CLAMP_MIN(value1, -1.0f); + CLAMP_MAX(value_max, 1.0f); + CLAMP_MIN(value_min, -1.0f); } - else { - immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f); + + bool is_line_strip = (value_max - value_min < 0.05f); + + if (was_line_strip != -1 && is_line_strip != was_line_strip) { + /* If the previously added strip type isn't the same as the current one, + * add transision areas so they transistion smoothly between each other. + */ + if (is_line_strip) { + /* This will be a line strip, end the tri strip. */ + tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel; + tri_strip_iter->pos[1] = y_mid + value_min * y_scale; + tri_strip_iter->clip = clipping; + tri_strip_iter->rms_pos = tri_strip_iter->pos[1]; + tri_strip_iter->end = true; + + /* End of section. */ + tri_strip_iter++; + + /* Check if we are at the end. + * If so, skip one point line. */ + if (i + 1 == pix_strip_len) { + continue; + } + } + else { + /* This will be a tri strip. */ + line_strip_iter--; + tri_strip_iter->pos[0] = line_strip_iter->pos[0]; + tri_strip_iter->pos[1] = line_strip_iter->pos[1]; + tri_strip_iter->clip = line_strip_iter->clip; + tri_strip_iter->rms_pos = line_strip_iter->pos[1]; + tri_strip_iter++; + + /* Check if line had only one point. */ + line_strip_iter--; + if (line_strip_iter < line_strip_arr || line_strip_iter->end) { + /* Only one point, skip it. */ + line_strip_iter++; + } + else { + /* End of section. */ + line_strip_iter++; + line_strip_iter->end = true; + line_strip_iter++; + } + } } - immVertex2f(pos, x1_offset + i * stepsize, ymid + value1 * yscale); - immVertex2f(pos, x1_offset + i * stepsize, ymid + value2 * yscale); + was_line_strip = is_line_strip; + + if (is_line_strip) { + line_strip_iter->pos[0] = x1_offset + i * frames_per_pixel; + line_strip_iter->pos[1] = y_mid + value_min * y_scale; + line_strip_iter->clip = clipping; + line_strip_iter++; + } + else { + tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel; + tri_strip_iter->pos[1] = y_mid + value_min * y_scale; + tri_strip_iter->clip = clipping; + tri_strip_iter->rms_pos = y_mid + max_ff(-rms, value_min) * y_scale; + tri_strip_iter++; + + tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel; + tri_strip_iter->pos[1] = y_mid + value_max * y_scale; + tri_strip_iter->clip = clipping; + tri_strip_iter->rms_pos = y_mid + min_ff(rms, value_max) * y_scale; + tri_strip_iter++; + } } - immEnd(); - immUnbindProgram(); - GPU_blend(GPU_BLEND_NONE); + WaveVizData *tri_strip_end = tri_strip_iter; + WaveVizData *line_strip_end = line_strip_iter; + + tri_strip_iter = tri_strip_arr; + line_strip_iter = line_strip_arr; + + draw_waveform(line_strip_iter, line_strip_end, GPU_PRIM_LINE_STRIP, false); + draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, false); + draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, true); + + MEM_freeN(tri_strip_arr); + MEM_freeN(line_strip_arr); } } @@ -1127,7 +1315,7 @@ static void draw_seq_strip(const bContext *C, } else { text_margin_y = y2; - y_threshold = 1; + y_threshold = false; } uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); -- cgit v1.2.3 From 118946d1953fb4e1bfd978d5ecef3151b98880a1 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Mon, 16 Aug 2021 14:35:23 +0200 Subject: Fix T87967: M2T video seeking is broken Bug caused by integer overflow in ffmpeg_generic_seek_workaround(). Function max_ii() was used to limit int_64tvalue. After fixing the issue there was another issue, where near-infinite loop was caused by requested_pos being very large and stream being cut in a way, that it was missing keyframe at beginning. This was fixed by checking if we are reading beyond file content. Reviewed By: zeddb Differential Revision: https://developer.blender.org/D11888 --- source/blender/imbuf/intern/anim_movie.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 2998c4781b6..dbca16ca82b 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1213,7 +1213,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, /* Step backward frame by frame until we find the key frame we are looking for. */ while (current_pts != 0) { current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame); - current_pts = max_ii(current_pts, 0); + current_pts = MAX2(current_pts, 0); /* Seek to timestamp. */ if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < @@ -1243,11 +1243,12 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, /* We found the I-frame we were looking for! */ break; } - if (cur_pts == prev_pts) { - /* We got the same key frame packet twice. - * This probably means that we have hit the beginning of the stream. */ - break; - } + } + + if (cur_pts == prev_pts) { + /* We got the same key frame packet twice. + * This probably means that we have hit the beginning of the stream. */ + break; } prev_pts = cur_pts; -- cgit v1.2.3 From 394a0b0da5b899944d33a38c9ff01e03dc370f2a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 23:19:54 +1000 Subject: Fix building without audaspace --- source/blender/blenkernel/intern/sound.c | 3 ++- source/blender/sequencer/intern/strip_add.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 9d287377545..bd0fbd840ff 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -1312,7 +1312,8 @@ void BKE_sound_move_scene_sound(Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe), int UNUSED(endframe), - int UNUSED(frameskip)) + int UNUSED(frameskip), + double UNUSED(audio_offset)) { } void BKE_sound_move_scene_sound_defaults(Scene *UNUSED(scene), Sequence *UNUSED(sequence)) diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index cc70cc38ebb..27e92550bbb 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -463,7 +463,8 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain), Scene *UNUSED(scene), ListBase *UNUSED(seqbase), - SeqLoadData *UNUSED(load_data)) + SeqLoadData *UNUSED(load_data), + const double UNUSED(audio_offset)) { return NULL; } -- cgit v1.2.3 From 7db3746033437783411b0eb4b77f0804c25e2614 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Aug 2021 23:46:28 +1000 Subject: Cleanup: spelling --- source/blender/editors/space_sequencer/sequencer_draw.c | 15 +++++++-------- source/blender/editors/space_sequencer/sequencer_edit.c | 2 +- source/blender/sequencer/intern/strip_add.c | 9 ++++----- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 888e232ce45..b3c39e2fa6f 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -329,10 +329,10 @@ static void draw_seq_waveform_overlay(View2D *v2d, { if (seq->sound && ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { /* Make sure that the start drawing position is aligned to the pixels on the screen to avoid - * flickering whem moving around the strip. + * flickering when moving around the strip. * To do this we figure out the fractional offset in pixel space by checking where the * window starts. - * We then append this pixel offset to our strip start coordiate to ensure we are aligned to + * We then append this pixel offset to our strip start coordinate to ensure we are aligned to * the screen pixel grid. */ float pixel_frac = v2d->cur.xmin / frames_per_pixel - floor(v2d->cur.xmin / frames_per_pixel); float x1_adj = clamp_frame_coord_to_pixel(x1, pixel_frac, frames_per_pixel); @@ -386,7 +386,7 @@ static void draw_seq_waveform_overlay(View2D *v2d, /* The y coordinate for the middle of the strip. */ float y_mid = (y1 + y2) / 2.0f; - /* The lenght from the middle of the strip to the top/bottom. */ + /* The length from the middle of the strip to the top/bottom. */ float y_scale = (y2 - y1) / 2.0f; float volume = seq->volume; @@ -403,9 +403,9 @@ static void draw_seq_waveform_overlay(View2D *v2d, if (strip_start_offset != 0) { /* If start offset is not zero, we need to make sure that we pick the same start sample as if - * we simply scrolled the start of the strip offscreen. Otherwise we will get flickering when - * changing start offset as the pixel alignment will not be the same for the drawn samples. - */ + * we simply scrolled the start of the strip off-screen. Otherwise we will get flickering + * when changing start offset as the pixel alignment will not be the same for the drawn + * samples. */ strip_start_offset = clamp_frame_coord_to_pixel( x1 - strip_start_offset, pixel_frac, frames_per_pixel); start_sample = fabsf(strip_start_offset - x1_adj) * samples_per_frame; @@ -470,8 +470,7 @@ static void draw_seq_waveform_overlay(View2D *v2d, if (was_line_strip != -1 && is_line_strip != was_line_strip) { /* If the previously added strip type isn't the same as the current one, - * add transision areas so they transistion smoothly between each other. - */ + * add transition areas so they transition smoothly between each other. */ if (is_line_strip) { /* This will be a line strip, end the tri strip. */ tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel; diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 4b26469aad3..afad8999e88 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2943,7 +2943,7 @@ static int seq_cmp_time_startdisp_channel(const void *a, const void *b) int seq_a_start = SEQ_transform_get_left_handle_frame(seq_a); int seq_b_start = SEQ_transform_get_left_handle_frame(seq_b); - /** If strips have the same start frame favor the one with a higher channel. **/ + /* If strips have the same start frame favor the one with a higher channel. */ if (seq_a_start == seq_b_start) { return seq_a->machine > seq_b->machine; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 27e92550bbb..7b383bcb330 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -426,12 +426,11 @@ Sequence *SEQ_add_sound_strip(Main *bmain, seq->sound = sound; seq->scene_sound = NULL; - /* We round the frame duration as the audio sample lenghts usually does not + /* We round the frame duration as the audio sample lengths usually does not * line up with the video frames. Therefore we round this number to the - * nearsest frame as the audio track usually overshoots or undershoots the - * end frame ofthe video by a little bit. - * See T47135 for under shoot example. - */ + * nearest frame as the audio track usually overshoots or undershoots the + * end frame of the video by a little bit. + * See T47135 for under shoot example. */ seq->len = MAX2(1, round((info.length - sound->offset_time) * FPS)); Strip *strip = seq->strip; -- cgit v1.2.3 From 035d4c28abaf351b36ff5bb6057f865888790331 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 16 Aug 2021 16:50:54 +0200 Subject: Add sanity NULL checks when loading sound sequences Would cause crashes in files that had lingering invalid sound sequences around. For example our tests/render/volume/fire.blend test file. --- source/blender/blenkernel/intern/sound.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index bd0fbd840ff..8730d2758e6 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -703,7 +703,7 @@ void *BKE_sound_scene_add_scene_sound( Scene *scene, Sequence *sequence, int startframe, int endframe, int frameskip) { sound_verify_evaluated_id(&scene->id); - if (sequence->scene && scene != sequence->scene) { + if (sequence->scene && scene != sequence->scene && sequence->sound) { const double fps = FPS; return AUD_Sequence_add(scene->sound_scene, sequence->scene->sound_scene, @@ -775,7 +775,7 @@ void BKE_sound_move_scene_sound( void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence) { sound_verify_evaluated_id(&scene->id); - if (sequence->scene_sound) { + if (sequence->scene_sound && sequence->sound) { BKE_sound_move_scene_sound(scene, sequence->scene_sound, sequence->startdisp, -- cgit v1.2.3 From b5117660da27d9d13c48c1d2f1afd64083e120bb Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 16 Aug 2021 13:49:06 -0300 Subject: PyAPI: GPU Buffer: Buffer protocol support The code was commented due to lack of testing and short release deadline. --- source/blender/python/gpu/gpu_py_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index a1fc89e772e..6e6aef4204d 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -37,7 +37,7 @@ #include "gpu_py_buffer.h" -//#define PYGPU_BUFFER_PROTOCOL +#define PYGPU_BUFFER_PROTOCOL #define MAX_DIMENSIONS 64 /* -------------------------------------------------------------------- */ -- cgit v1.2.3 From 4dba2060118b43699a40ae04a66f75ba5f9c745e Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 16 Aug 2021 13:53:56 -0300 Subject: PyAPI: GPUShader: make 'uniform_vector_*' less restricted Buffers larger than required may be allowed without restriction. --- source/blender/python/gpu/gpu_py_shader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index 41c40fdeb96..145586d8ab0 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -211,8 +211,9 @@ static bool pygpu_shader_uniform_vector_impl(PyObject *args, return false; } - if (r_pybuffer->len != (*r_length * *r_count * elem_size)) { - PyErr_SetString(PyExc_BufferError, "GPUShader.uniform_vector_*: buffer size does not match."); + if (r_pybuffer->len < (*r_length * *r_count * elem_size)) { + PyErr_SetString(PyExc_OverflowError, + "GPUShader.uniform_vector_*: buffer size smaller than required."); return false; } -- cgit v1.2.3 From eaa152738523bdd2163330fda7ffb1ad62e559cd Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Mon, 16 Aug 2021 21:19:39 -0700 Subject: UDIM: Fix tile number calculation when adding a range of image tiles When adding a range of tiles, the operator could incorrectly calculate the end_tile. It would not account for the start_tile itself and the IMA_UDIM_MAX value was 1 too small. This is most noticeable when attempting to fill the entire supported range of tiles. Differential Revision: https://developer.blender.org/D11857 --- source/blender/blenkernel/BKE_image.h | 2 +- source/blender/editors/space_image/image_ops.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index d298e5dcf6d..ac73bd2b595 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -45,7 +45,7 @@ struct StampData; struct anim; #define IMA_MAX_SPACE 64 -#define IMA_UDIM_MAX 1999 +#define IMA_UDIM_MAX 2000 void BKE_images_init(void); void BKE_images_exit(void); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 613042a2ab9..999d2956fef 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3922,7 +3922,7 @@ static int tile_add_exec(bContext *C, wmOperator *op) Image *ima = CTX_data_edit_image(C); int start_tile = RNA_int_get(op->ptr, "number"); - int end_tile = start_tile + RNA_int_get(op->ptr, "count"); + int end_tile = start_tile + RNA_int_get(op->ptr, "count") - 1; if (start_tile < 1001 || end_tile > IMA_UDIM_MAX) { BKE_report(op->reports, RPT_ERROR, "Invalid UDIM index range was specified"); @@ -3933,7 +3933,7 @@ static int tile_add_exec(bContext *C, wmOperator *op) char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0); bool created_tile = false; - for (int tile_number = start_tile; tile_number < end_tile; tile_number++) { + for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) { ImageTile *tile = BKE_image_add_tile(ima, tile_number, label); if (tile != NULL) { @@ -3949,6 +3949,7 @@ static int tile_add_exec(bContext *C, wmOperator *op) MEM_freeN(label); if (!created_tile) { + BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created"); return OPERATOR_CANCELLED; } -- cgit v1.2.3 From 869b84452a8c06c505fcd265510727248b059a59 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 14:42:12 +1000 Subject: Cleanup: compiler warnings --- source/blender/python/gpu/gpu_py_buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index 6e6aef4204d..0fef59d6352 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -608,7 +608,7 @@ static void pygpu_buffer_strides_calc(const eGPUDataFormat format, } /* Here is the buffer interface function */ -static int pygpu_buffer__bf_getbuffer(BPyGPUBuffer *self, Py_buffer *view, int flags) +static int pygpu_buffer__bf_getbuffer(BPyGPUBuffer *self, Py_buffer *view, int UNUSED(flags)) { if (view == NULL) { PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer"); @@ -620,7 +620,7 @@ static int pygpu_buffer__bf_getbuffer(BPyGPUBuffer *self, Py_buffer *view, int f view->len = bpygpu_Buffer_size(self); view->readonly = 0; view->itemsize = GPU_texture_dataformat_size(self->format); - view->format = pygpu_buffer_formatstr(self->format); + view->format = (char *)pygpu_buffer_formatstr(self->format); view->ndim = self->shape_len; view->shape = self->shape; view->strides = MEM_mallocN(view->ndim * sizeof(*view->strides), "BPyGPUBuffer strides"); -- cgit v1.2.3 From d60e28093f8b3145d099ca696e0ddc2d0c9850ed Mon Sep 17 00:00:00 2001 From: nutti Date: Tue, 17 Aug 2021 14:44:28 +1000 Subject: Docs: add API docs for gpu.platform Adds Python API documentations for gpu.platform module. Ref D12222 --- source/blender/python/gpu/gpu_py_platform.c | 30 ++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index 132052b6f1d..7d10f0e9b43 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -33,16 +33,37 @@ /** \name Functions * \{ */ +PyDoc_STRVAR(pygpu_platform_vendor_get_doc, + ".. function:: vendor_get()\n" + "\n" + " Get GPU vendor.\n" + "\n" + " :return: Vendor name.\n" + " :rtype: str\n"); static PyObject *pygpu_platform_vendor_get(PyObject *UNUSED(self)) { return PyUnicode_FromString(GPU_platform_vendor()); } +PyDoc_STRVAR(pygpu_platform_renderer_get_doc, + ".. function:: renderer_get()\n" + "\n" + " Get GPU to be used for rendering.\n" + "\n" + " :return: GPU name.\n" + " :rtype: str\n"); static PyObject *pygpu_platform_renderer_get(PyObject *UNUSED(self)) { return PyUnicode_FromString(GPU_platform_renderer()); } +PyDoc_STRVAR(pygpu_platform_version_get_doc, + ".. function:: version_get()\n" + "\n" + " Get GPU driver version.\n" + "\n" + " :return: Driver version.\n" + " :rtype: str\n"); static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self)) { return PyUnicode_FromString(GPU_platform_version()); @@ -55,9 +76,12 @@ static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self)) * \{ */ static struct PyMethodDef pygpu_platform__tp_methods[] = { - {"vendor_get", (PyCFunction)pygpu_platform_vendor_get, METH_NOARGS, NULL}, - {"renderer_get", (PyCFunction)pygpu_platform_renderer_get, METH_NOARGS, NULL}, - {"version_get", (PyCFunction)pygpu_platform_version_get, METH_NOARGS, NULL}, + {"vendor_get", (PyCFunction)pygpu_platform_vendor_get, METH_NOARGS, + pygpu_platform_vendor_get_doc}, + {"renderer_get", (PyCFunction)pygpu_platform_renderer_get, METH_NOARGS, + pygpu_platform_renderer_get_doc}, + {"version_get", (PyCFunction)pygpu_platform_version_get, METH_NOARGS, + pygpu_platform_version_get_doc}, {NULL, NULL, 0, NULL}, }; -- cgit v1.2.3 From ba055493a05a1dbf609dece130cc1ac334f50228 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 14:46:46 +1000 Subject: Cleanup: clang-format --- source/blender/gpu/GPU_texture.h | 9 +++++++-- .../nodes/geometry/nodes/node_geo_subdivision_surface.cc | 11 +++++++---- source/blender/python/gpu/gpu_py_platform.c | 12 +++++++++--- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index ee4d08d4059..9a1885160b6 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -192,8 +192,13 @@ GPUTexture *GPU_texture_create_1d_array( const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data); GPUTexture *GPU_texture_create_2d( const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data); -GPUTexture *GPU_texture_create_2d_array( - const char *name, int w, int h, int d, int mip_len, eGPUTextureFormat format, const float *data); +GPUTexture *GPU_texture_create_2d_array(const char *name, + int w, + int h, + int d, + int mip_len, + eGPUTextureFormat format, + const float *data); GPUTexture *GPU_texture_create_3d(const char *name, int w, int h, diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 7882cd04845..e8dd36e528c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -18,9 +18,9 @@ #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.h" +#include "DNA_modifier_types.h" #include "UI_interface.h" #include "UI_resources.h" -#include "DNA_modifier_types.h" #include "node_geometry_util.hh" static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { @@ -74,7 +74,8 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, TIP_("Disabled, Blender was compiled without OpenSubdiv")); #else - const NodeGeometrySubdivisionSurface &storage = *(const NodeGeometrySubdivisionSurface *)params.node().storage; + const NodeGeometrySubdivisionSurface &storage = + *(const NodeGeometrySubdivisionSurface *)params.node().storage; const int uv_smooth = storage.uv_smooth; const int boundary_smooth = storage.boundary_smooth; const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 30); @@ -142,8 +143,10 @@ void register_node_type_geo_subdivision_surface() ntype.draw_buttons = geo_node_subdivision_surface_layout; node_type_init(&ntype, geo_node_subdivision_surface_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_storage( - &ntype, "NodeGeometrySubdivisionSurface", node_free_standard_storage, node_copy_standard_storage); + node_type_storage(&ntype, + "NodeGeometrySubdivisionSurface", + node_free_standard_storage, + node_copy_standard_storage); node_type_socket_templates( &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); nodeRegisterType(&ntype); diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index 7d10f0e9b43..62310a83642 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -76,11 +76,17 @@ static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self)) * \{ */ static struct PyMethodDef pygpu_platform__tp_methods[] = { - {"vendor_get", (PyCFunction)pygpu_platform_vendor_get, METH_NOARGS, + {"vendor_get", + (PyCFunction)pygpu_platform_vendor_get, + METH_NOARGS, pygpu_platform_vendor_get_doc}, - {"renderer_get", (PyCFunction)pygpu_platform_renderer_get, METH_NOARGS, + {"renderer_get", + (PyCFunction)pygpu_platform_renderer_get, + METH_NOARGS, pygpu_platform_renderer_get_doc}, - {"version_get", (PyCFunction)pygpu_platform_version_get, METH_NOARGS, + {"version_get", + (PyCFunction)pygpu_platform_version_get, + METH_NOARGS, pygpu_platform_version_get_doc}, {NULL, NULL, 0, NULL}, }; -- cgit v1.2.3 From 69fdcea9788caa1c94e2baf848eeb6650b274c6b Mon Sep 17 00:00:00 2001 From: nutti Date: Tue, 17 Aug 2021 14:55:05 +1000 Subject: Docs: add API docs for gpu.capabilities Adds Python API documentations for gpu.capabilities module. Ref D12226 --- source/blender/python/gpu/gpu_py_capabilities.c | 162 ++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 13 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/gpu/gpu_py_capabilities.c b/source/blender/python/gpu/gpu_py_capabilities.c index f3fb93021b2..11e7d48f096 100644 --- a/source/blender/python/gpu/gpu_py_capabilities.c +++ b/source/blender/python/gpu/gpu_py_capabilities.c @@ -33,66 +33,166 @@ /** \name Functions * \{ */ +PyDoc_STRVAR(pygpu_max_texture_size_get_doc, + ".. function:: max_texture_size_get()\n" + "\n" + " Get estimated maximum texture size to be able to handle.\n" + "\n" + " :return: Texture size.\n" + " :rtype: int\n"); static PyObject *pygpu_max_texture_size_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_texture_size()); } +PyDoc_STRVAR(pygpu_max_texture_layers_get_doc, + ".. function:: max_texture_layers_get()\n" + "\n" + " Get maximum number of layers in texture.\n" + "\n" + " :return: Number of layers.\n" + " :rtype: int\n"); static PyObject *pygpu_max_texture_layers_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_texture_layers()); } +PyDoc_STRVAR(pygpu_max_textures_get_doc, + ".. function:: max_textures_get()\n" + "\n" + " Get maximum supported texture image units used for\n" + " accessing texture maps from the vertex shader and the\n" + " fragment processor.\n" + "\n" + " :return: Texture image units.\n" + " :rtype: int\n"); static PyObject *pygpu_max_textures_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_textures()); } +PyDoc_STRVAR(pygpu_max_textures_vert_get_doc, + ".. function:: max_textures_vert_get()\n" + "\n" + " Get maximum supported texture image units used for\n" + " accessing texture maps from the vertex shader.\n" + "\n" + " :return: Texture image units.\n" + " :rtype: int\n"); static PyObject *pygpu_max_textures_vert_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_textures_vert()); } +PyDoc_STRVAR(pygpu_max_textures_geom_get_doc, + ".. function:: max_textures_geom_get()\n" + "\n" + " Get maximum supported texture image units used for\n" + " accessing texture maps from the geometry shader.\n" + "\n" + " :return: Texture image units.\n" + " :rtype: int\n"); static PyObject *pygpu_max_textures_geom_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_textures_geom()); } +PyDoc_STRVAR(pygpu_max_textures_frag_get_doc, + ".. function:: max_textures_frag_get()\n" + "\n" + " Get maximum supported texture image units used for\n" + " accessing texture maps from the fragment shader.\n" + "\n" + " :return: Texture image units.\n" + " :rtype: int\n"); static PyObject *pygpu_max_textures_frag_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_textures_frag()); } +PyDoc_STRVAR(pygpu_max_uniforms_vert_get_doc, + ".. function:: max_uniforms_vert_get()\n" + "\n" + " Get maximum number of values held in uniform variable\n" + " storage for a vertex shader.\n" + "\n" + " :return: Number of values.\n" + " :rtype: int\n"); static PyObject *pygpu_max_uniforms_vert_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_uniforms_vert()); } +PyDoc_STRVAR(pygpu_max_uniforms_frag_get_doc, + ".. function:: max_uniforms_frag_get()\n" + "\n" + " Get maximum number of values held in uniform variable\n" + " storage for a fragment shader.\n" + "\n" + " :return: Number of values.\n" + " :rtype: int\n"); static PyObject *pygpu_max_uniforms_frag_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_uniforms_frag()); } +PyDoc_STRVAR(pygpu_max_batch_indices_get_doc, + ".. function:: max_batch_indices_get()\n" + "\n" + " Get maximum number of vertex array indices.\n" + "\n" + " :return: Number of indices.\n" + " :rtype: int\n"); static PyObject *pygpu_max_batch_indices_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_batch_indices()); } +PyDoc_STRVAR(pygpu_max_batch_vertices_get_doc, + ".. function:: max_batch_vertices_get()\n" + "\n" + " Get maximum number of vertex array vertices.\n" + "\n" + " :return: Number of vertices.\n" + " :rtype: int\n"); static PyObject *pygpu_max_batch_vertices_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_batch_vertices()); } +PyDoc_STRVAR(pygpu_max_vertex_attribs_get_doc, + ".. function:: max_vertex_attribs_get()\n" + "\n" + " Get maximum number of vertex attributes accessible to\n" + " a vertex shader.\n" + "\n" + " :return: Number of attributes.\n" + " :rtype: int\n"); static PyObject *pygpu_max_vertex_attribs_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_vertex_attribs()); } +PyDoc_STRVAR(pygpu_max_varying_floats_get_doc, + ".. function:: max_varying_floats_get()\n" + "\n" + " Get maximum number of varying variables used by\n" + " vertex and fragment shaders.\n" + "\n" + " :return: Number of variables.\n" + " :rtype: int\n"); static PyObject *pygpu_max_varying_floats_get(PyObject *UNUSED(self)) { return PyLong_FromLong(GPU_max_varying_floats()); } +PyDoc_STRVAR(pygpu_extensions_get_doc, + ".. function:: extensions_get()\n" + "\n" + " Get supported extensions in the current context.\n" + "\n" + " :return: Extensions.\n" + " :rtype: tuple of string\n"); static PyObject *pygpu_extensions_get(PyObject *UNUSED(self)) { int extensions_len = GPU_extensions_len(); @@ -112,19 +212,55 @@ static PyObject *pygpu_extensions_get(PyObject *UNUSED(self)) * \{ */ static struct PyMethodDef pygpu_capabilities__tp_methods[] = { - {"max_texture_size_get", (PyCFunction)pygpu_max_texture_size_get, METH_NOARGS, NULL}, - {"max_texture_layers_get", (PyCFunction)pygpu_max_texture_layers_get, METH_NOARGS, NULL}, - {"max_textures_get", (PyCFunction)pygpu_max_textures_get, METH_NOARGS, NULL}, - {"max_textures_vert_get", (PyCFunction)pygpu_max_textures_vert_get, METH_NOARGS, NULL}, - {"max_textures_geom_get", (PyCFunction)pygpu_max_textures_geom_get, METH_NOARGS, NULL}, - {"max_textures_frag_get", (PyCFunction)pygpu_max_textures_frag_get, METH_NOARGS, NULL}, - {"max_uniforms_vert_get", (PyCFunction)pygpu_max_uniforms_vert_get, METH_NOARGS, NULL}, - {"max_uniforms_frag_get", (PyCFunction)pygpu_max_uniforms_frag_get, METH_NOARGS, NULL}, - {"max_batch_indices_get", (PyCFunction)pygpu_max_batch_indices_get, METH_NOARGS, NULL}, - {"max_batch_vertices_get", (PyCFunction)pygpu_max_batch_vertices_get, METH_NOARGS, NULL}, - {"max_vertex_attribs_get", (PyCFunction)pygpu_max_vertex_attribs_get, METH_NOARGS, NULL}, - {"max_varying_floats_get", (PyCFunction)pygpu_max_varying_floats_get, METH_NOARGS, NULL}, - {"extensions_get", (PyCFunction)pygpu_extensions_get, METH_NOARGS, NULL}, + {"max_texture_size_get", + (PyCFunction)pygpu_max_texture_size_get, + METH_NOARGS, + pygpu_max_texture_size_get_doc}, + {"max_texture_layers_get", + (PyCFunction)pygpu_max_texture_layers_get, + METH_NOARGS, + pygpu_max_texture_layers_get_doc}, + {"max_textures_get", + (PyCFunction)pygpu_max_textures_get, + METH_NOARGS, + pygpu_max_textures_get_doc}, + {"max_textures_vert_get", + (PyCFunction)pygpu_max_textures_vert_get, + METH_NOARGS, + pygpu_max_textures_vert_get_doc}, + {"max_textures_geom_get", + (PyCFunction)pygpu_max_textures_geom_get, + METH_NOARGS, + pygpu_max_textures_geom_get_doc}, + {"max_textures_frag_get", + (PyCFunction)pygpu_max_textures_frag_get, + METH_NOARGS, + pygpu_max_textures_frag_get_doc}, + {"max_uniforms_vert_get", + (PyCFunction)pygpu_max_uniforms_vert_get, + METH_NOARGS, + pygpu_max_uniforms_vert_get_doc}, + {"max_uniforms_frag_get", + (PyCFunction)pygpu_max_uniforms_frag_get, + METH_NOARGS, + pygpu_max_uniforms_frag_get_doc}, + {"max_batch_indices_get", + (PyCFunction)pygpu_max_batch_indices_get, + METH_NOARGS, + pygpu_max_batch_indices_get_doc}, + {"max_batch_vertices_get", + (PyCFunction)pygpu_max_batch_vertices_get, + METH_NOARGS, + pygpu_max_batch_vertices_get_doc}, + {"max_vertex_attribs_get", + (PyCFunction)pygpu_max_vertex_attribs_get, + METH_NOARGS, + pygpu_max_vertex_attribs_get_doc}, + {"max_varying_floats_get", + (PyCFunction)pygpu_max_varying_floats_get, + METH_NOARGS, + pygpu_max_varying_floats_get_doc}, + {"extensions_get", (PyCFunction)pygpu_extensions_get, METH_NOARGS, pygpu_extensions_get_doc}, {NULL, NULL, 0, NULL}, }; -- cgit v1.2.3 From 736b6a70a492e35c2be9e1f6bb6b26a057fbdf58 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 15:11:54 +1000 Subject: Docs: improve word wrap comment --- source/blender/blenkernel/intern/font.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index de838f1b3cd..72add476bfe 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -716,8 +716,10 @@ typedef struct VFontToCurveIter { } bisect; bool ok; /** - * Disables checking if word wrapping is needed to fit the text-box width. - * Currently only used when scale-to-fit is enabled. + * Wrap words that extends beyond the text-box width (enabled by default). + * + * Currently only disabled when scale-to-fit is enabled, + * so floating-point error doesn't cause unexpected wrapping, see T89241. */ bool word_wrap; int status; -- cgit v1.2.3 From 4c8d68c03293a36fd28b3401833a465f24020ce5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 15:14:09 +1000 Subject: Cleanup: replace degenerate check with assert Use an assert since this should never happen. --- source/blender/bmesh/intern/bmesh_mesh_normals.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c index a5e41b74ee1..186c85abe58 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.c +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c @@ -85,10 +85,9 @@ BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter, dotprod = -dotprod; } const float fac = saacos(-dotprod); - /* NAN detection, otherwise this is a degenerated case, ignore that vertex in this case. */ - if (fac == fac) { - madd_v3_v3fl(v_no, f_no, fac); - } + /* Shouldn't happen as normalizing edge-vectors cause degenerate values to be zeroed out. */ + BLI_assert(!isnan(fac)); + madd_v3_v3fl(v_no, f_no, fac); } static void bm_vert_calc_normals_impl(BMVert *v) -- cgit v1.2.3 From cb40c7ca1f4bbbbee5efc4fee6e1dcf8709a8bc4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 16:46:09 +1000 Subject: Fix memory leak in edit-mesh dissolve degenerate --- source/blender/editors/mesh/editmesh_tools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1b6643da1aa..186c98eb8da 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -6314,7 +6314,7 @@ static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; if (!EDBM_op_callf(em, op, "dissolve_degenerate edges=%he dist=%f", BM_ELEM_SELECT, thresh)) { - return OPERATOR_CANCELLED; + continue; } /* tricky to maintain correct selection here, so just flush up from verts */ -- cgit v1.2.3 From 6baa62245f2bc18cc6d12cfcd16575823028bcab Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 17:10:59 +1000 Subject: Edit Mesh: skip flipping custom normals for meshes with no selection Also split out normal calculation into functions. --- source/blender/editors/mesh/editmesh_tools.c | 111 +++++++++++++++------------ 1 file changed, 63 insertions(+), 48 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 186c98eb8da..b62eee67600 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2183,6 +2183,61 @@ static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) /* -------------------------------------------------------------------- */ /** \name Flip Normals Operator * \{ */ + +static void edbm_flip_normals_custom_loop_normals(Object *obedit, BMEditMesh *em) +{ + if (!CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) { + return; + } + + /* The mesh has custom normal data, flip them. */ + BMesh *bm = em->bm; + + BM_lnorspace_update(bm); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + negate_v3(lnor_ed->nloc); + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + BM_loop_normal_editdata_array_free(lnors_ed_arr); + EDBM_update(obedit->data, + &(const struct EDBMUpdate_Params){ + .calc_looptri = true, + .calc_normals = false, + .is_destructive = false, + }); +} + +static void edbm_flip_normals_face_winding(wmOperator *op, Object *obedit, BMEditMesh *em) +{ + + bool has_flipped_faces = false; + + /* See if we have any custom normals to flip. */ + BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm); + + if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { + has_flipped_faces = true; + } + + if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) { + EDBM_update(obedit->data, + &(const struct EDBMUpdate_Params){ + .calc_looptri = true, + .calc_normals = false, + .is_destructive = false, + }); + } + + if (lnors_ed_arr != NULL) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } +} + static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors"); @@ -2197,56 +2252,16 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); if (only_clnors) { - if (CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) { - /* The mesh has custom normal data, flip them. */ - BMesh *bm = em->bm; - - BM_lnorspace_update(bm); - BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); - BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; - - for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { - negate_v3(lnor_ed->nloc); - - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], - lnor_ed->nloc, - lnor_ed->clnors_data); - } - BM_loop_normal_editdata_array_free(lnors_ed_arr); - EDBM_update(obedit->data, - &(const struct EDBMUpdate_Params){ - .calc_looptri = true, - .calc_normals = false, - .is_destructive = false, - }); + if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; } - continue; - } - - if (em->bm->totfacesel == 0) { - continue; - } - - bool has_flipped_faces = false; - - /* See if we have any custom normals to flip. */ - BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm); - - if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { - has_flipped_faces = true; + edbm_flip_normals_custom_loop_normals(obedit, em); } - - if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) { - EDBM_update(obedit->data, - &(const struct EDBMUpdate_Params){ - .calc_looptri = true, - .calc_normals = false, - .is_destructive = false, - }); - } - - if (lnors_ed_arr != NULL) { - BM_loop_normal_editdata_array_free(lnors_ed_arr); + else { + if (em->bm->totfacesel == 0) { + continue; + } + edbm_flip_normals_face_winding(op, obedit, em); } } -- cgit v1.2.3 From 4443831c6bc264f6017a309b6217beb72943abee Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 17:11:00 +1000 Subject: Edit Mesh: skip normals to vector with unselected meshes for "Delete" Meshes with unselected elements are skipped but still called BM_custom_loop_normals_to_vector_layer. --- source/blender/editors/mesh/editmesh_tools.c | 46 +++++++++++++++++----------- 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index b62eee67600..101c997fd1c 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -467,40 +467,50 @@ static int edbm_delete_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const int type = RNA_enum_get(op->ptr, "type"); - BM_custom_loop_normals_to_vector_layer(em->bm); - switch (type) { case MESH_DELETE_VERT: /* Erase Vertices */ - if (!(em->bm->totvertsel && - EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS))) { + if (em->bm->totvertsel == 0) { + continue; + } + BM_custom_loop_normals_to_vector_layer(em->bm); + if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) { continue; } break; case MESH_DELETE_EDGE: /* Erase Edges */ - if (!(em->bm->totedgesel && - EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES))) { + if (em->bm->totedgesel == 0) { + continue; + } + BM_custom_loop_normals_to_vector_layer(em->bm); + if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) { continue; } break; case MESH_DELETE_FACE: /* Erase Faces */ - if (!(em->bm->totfacesel && - EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES))) { + if (em->bm->totfacesel == 0) { + continue; + } + BM_custom_loop_normals_to_vector_layer(em->bm); + if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) { continue; } break; - case MESH_DELETE_EDGE_FACE: - /* Edges and Faces */ - if (!((em->bm->totedgesel || em->bm->totfacesel) && - EDBM_op_callf( - em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))) { + case MESH_DELETE_EDGE_FACE: /* Edges and Faces */ + if ((em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { + continue; + } + BM_custom_loop_normals_to_vector_layer(em->bm); + if (!EDBM_op_callf( + em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) { continue; } break; - case MESH_DELETE_ONLY_FACE: - /* Only faces. */ - if (!(em->bm->totfacesel && - EDBM_op_callf( - em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))) { + case MESH_DELETE_ONLY_FACE: /* Only faces. */ + if (em->bm->totfacesel == 0) { + continue; + } + BM_custom_loop_normals_to_vector_layer(em->bm); + if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES)) { continue; } break; -- cgit v1.2.3 From 32844d32c1d90e6205145ef3bdde2f9281127c82 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 17:11:02 +1000 Subject: Edit Mesh: skip unselected meshes for "Set Normals from Faces" --- source/blender/editors/mesh/editmesh_tools.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 101c997fd1c..fa0762ee0bf 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -9531,6 +9531,10 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; + if (bm->totfacesel == 0) { + continue; + } + BMFace *f; BMVert *v; BMEdge *e; -- cgit v1.2.3 From 7304541f66a87e8131e9654a7fa1b9e77fb1fa4e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 17:11:03 +1000 Subject: Edit Mesh: skip unselected meshes for "Tris to Quads" Also move property assignment out of the object loop. --- source/blender/editors/mesh/editmesh_tools.c | 33 +++++++++++++++------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index fa0762ee0bf..b8bbf2d3e70 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -5576,24 +5576,24 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op) Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( view_layer, CTX_wm_view3d(C), &objects_len); - bool is_face_pair; + const bool do_seam = RNA_boolean_get(op->ptr, "seam"); + const bool do_sharp = RNA_boolean_get(op->ptr, "sharp"); + const bool do_uvs = RNA_boolean_get(op->ptr, "uvs"); + const bool do_vcols = RNA_boolean_get(op->ptr, "vcols"); + const bool do_materials = RNA_boolean_get(op->ptr, "materials"); + float angle_face_threshold, angle_shape_threshold; + bool is_face_pair; { int totelem_sel[3]; EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel); is_face_pair = (totelem_sel[2] == 2); } - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool do_seam, do_sharp, do_uvs, do_vcols, do_materials; - float angle_face_threshold, angle_shape_threshold; + /* When joining exactly 2 faces, no limit. + * this is useful for one off joins while editing. */ + { PropertyRNA *prop; - - /* When joining exactly 2 faces, no limit. - * this is useful for one off joins while editing. */ prop = RNA_struct_find_property(op->ptr, "face_threshold"); if (is_face_pair && (RNA_property_is_set(op->ptr, prop) == false)) { angle_face_threshold = DEG2RADF(180.0f); @@ -5609,12 +5609,15 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op) else { angle_shape_threshold = RNA_property_float_get(op->ptr, prop); } + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - do_seam = RNA_boolean_get(op->ptr, "seam"); - do_sharp = RNA_boolean_get(op->ptr, "sharp"); - do_uvs = RNA_boolean_get(op->ptr, "uvs"); - do_vcols = RNA_boolean_get(op->ptr, "vcols"); - do_materials = RNA_boolean_get(op->ptr, "materials"); + if (em->bm->totfacesel == 0) { + continue; + } BM_custom_loop_normals_to_vector_layer(em->bm); -- cgit v1.2.3 From 6028ac44a1351ef91a2fe3b98ab15f8690d885b5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 17 Aug 2021 17:45:57 +1000 Subject: Cleanup: unused defines --- source/blender/blenlib/tests/BLI_array_store_test.cc | 11 ----------- source/blender/bmesh/operators/bmo_removedoubles.c | 1 - source/blender/makesdna/DNA_object_types.h | 2 -- source/blender/windowmanager/WM_types.h | 9 ++++----- 4 files changed, 4 insertions(+), 19 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/tests/BLI_array_store_test.cc b/source/blender/blenlib/tests/BLI_array_store_test.cc index 8bbd109fb81..89aeccdc105 100644 --- a/source/blender/blenlib/tests/BLI_array_store_test.cc +++ b/source/blender/blenlib/tests/BLI_array_store_test.cc @@ -187,17 +187,6 @@ static void testbuffer_list_state_from_data__stride_expand(ListBase *lb, ((void)0) /* test in both directions */ -#define TESTBUFFER_STRINGS_EX(bs, ...) \ - { \ - ListBase lb; \ - TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \ -\ - testbuffer_run_tests(bs, &lb); \ -\ - testbuffer_list_free(&lb); \ - } \ - ((void)0) - #define TESTBUFFER_STRINGS(stride, chunk_count, ...) \ { \ ListBase lb; \ diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 8cc0bfadbda..57760900d45 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -327,7 +327,6 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) } #define VERT_KEEP 8 -#define VERT_IN 32 #define EDGE_MARK 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index c6d6334118f..0250d853898 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -467,8 +467,6 @@ typedef struct ObHook { /* used many places, should be specialized. */ #define SELECT 1 -#define OBJECT_ACTIVE_MODIFIER_NONE -1 - /* type */ enum { OB_EMPTY = 0, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 485d8e5a162..843ceca7700 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -328,11 +328,10 @@ typedef struct wmNotifier { #define ND_LAYOUTDELETE (2 << 16) #define ND_ANIMPLAY (4 << 16) #define ND_GPENCIL (5 << 16) -#define ND_EDITOR_CHANGED (6 << 16) /* Sent to new editors after switching to them. */ -#define ND_LAYOUTSET (7 << 16) -#define ND_SKETCH (8 << 16) -#define ND_WORKSPACE_SET (9 << 16) -#define ND_WORKSPACE_DELETE (10 << 16) +#define ND_LAYOUTSET (6 << 16) +#define ND_SKETCH (7 << 16) +#define ND_WORKSPACE_SET (8 << 16) +#define ND_WORKSPACE_DELETE (9 << 16) /* NC_SCENE Scene */ #define ND_SCENEBROWSE (1 << 16) -- cgit v1.2.3 From f8dd0080a9c490b017a95857ff750e79d4c6943a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 17 Aug 2021 11:12:59 +0200 Subject: Cleanup: clang tidy The parameter name was inconsistent between declaratation and implementation. --- source/blender/gpu/intern/gpu_texture.cc | 36 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'source/blender') diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 6564cbda694..d5d13ea269f 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -241,55 +241,61 @@ static inline GPUTexture *gpu_texture_create(const char *name, } GPUTexture *GPU_texture_create_1d( - const char *name, int w, int mips, eGPUTextureFormat format, const float *data) + const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data) { - return gpu_texture_create(name, w, 0, 0, GPU_TEXTURE_1D, mips, format, GPU_DATA_FLOAT, data); + return gpu_texture_create(name, w, 0, 0, GPU_TEXTURE_1D, mip_len, format, GPU_DATA_FLOAT, data); } GPUTexture *GPU_texture_create_1d_array( - const char *name, int w, int h, int mips, eGPUTextureFormat format, const float *data) + const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data) { return gpu_texture_create( - name, w, h, 0, GPU_TEXTURE_1D_ARRAY, mips, format, GPU_DATA_FLOAT, data); + name, w, h, 0, GPU_TEXTURE_1D_ARRAY, mip_len, format, GPU_DATA_FLOAT, data); } GPUTexture *GPU_texture_create_2d( - const char *name, int w, int h, int mips, eGPUTextureFormat format, const float *data) + const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data) { - return gpu_texture_create(name, w, h, 0, GPU_TEXTURE_2D, mips, format, GPU_DATA_FLOAT, data); + return gpu_texture_create(name, w, h, 0, GPU_TEXTURE_2D, mip_len, format, GPU_DATA_FLOAT, data); } -GPUTexture *GPU_texture_create_2d_array( - const char *name, int w, int h, int d, int mips, eGPUTextureFormat format, const float *data) +GPUTexture *GPU_texture_create_2d_array(const char *name, + int w, + int h, + int d, + int mip_len, + eGPUTextureFormat format, + const float *data) { return gpu_texture_create( - name, w, h, d, GPU_TEXTURE_2D_ARRAY, mips, format, GPU_DATA_FLOAT, data); + name, w, h, d, GPU_TEXTURE_2D_ARRAY, mip_len, format, GPU_DATA_FLOAT, data); } GPUTexture *GPU_texture_create_3d(const char *name, int w, int h, int d, - int mips, + int mip_len, eGPUTextureFormat texture_format, eGPUDataFormat data_format, const void *data) { return gpu_texture_create( - name, w, h, d, GPU_TEXTURE_3D, mips, texture_format, data_format, data); + name, w, h, d, GPU_TEXTURE_3D, mip_len, texture_format, data_format, data); } GPUTexture *GPU_texture_create_cube( - const char *name, int w, int mips, eGPUTextureFormat format, const float *data) + const char *name, int w, int mip_len, eGPUTextureFormat format, const float *data) { - return gpu_texture_create(name, w, w, 0, GPU_TEXTURE_CUBE, mips, format, GPU_DATA_FLOAT, data); + return gpu_texture_create( + name, w, w, 0, GPU_TEXTURE_CUBE, mip_len, format, GPU_DATA_FLOAT, data); } GPUTexture *GPU_texture_create_cube_array( - const char *name, int w, int d, int mips, eGPUTextureFormat format, const float *data) + const char *name, int w, int d, int mip_len, eGPUTextureFormat format, const float *data) { return gpu_texture_create( - name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mips, format, GPU_DATA_FLOAT, data); + name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mip_len, format, GPU_DATA_FLOAT, data); } /* DDS texture loading. Return NULL if support is not available. */ -- cgit v1.2.3 From 0246128b7f9c353641733f38dfafec362c3cf933 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 17 Aug 2021 15:10:50 +0200 Subject: Fix wrong Anim Auto-Snap Ctrl toggle This was not working like elsewhere in both NLA and Graph Editor (meaning that when snapping was already enabled, {key Ctrl} during transform did not disable it). Now use getAnimEdit_SnapMode() for this in NLA and GE as well. Maniphest Tasks: T87173 Differential Revision: https://developer.blender.org/D12244 --- source/blender/editors/transform/transform_convert_graph.c | 11 ++++++----- source/blender/editors/transform/transform_convert_nla.c | 4 +++- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index 111f81ff87b..a6cbbb299ac 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -41,6 +41,7 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_mode.h" typedef struct TransDataGraph { float unit_scale; @@ -656,7 +657,6 @@ static bool fcu_test_selected(FCurve *fcu) */ static void flushTransGraphData(TransInfo *t) { - SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; TransData *td; TransData2D *td2d; TransDataGraph *tdg; @@ -680,7 +680,8 @@ static void flushTransGraphData(TransInfo *t) * - Don't do this when canceling, or else these changes won't go away. */ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) { - switch (sipo->autosnap) { + const short autosnap = getAnimEdit_SnapMode(t); + switch (autosnap) { case SACTSNAP_FRAME: /* snap to nearest frame */ td2d->loc[0] = floor((double)td2d->loc[0] + 0.5); break; @@ -714,9 +715,9 @@ static void flushTransGraphData(TransInfo *t) * * \note We don't do this when canceling transforms, or else these changes don't go away. */ - if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 && - ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP)) { - switch (sipo->autosnap) { + if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) { + const short autosnap = getAnimEdit_SnapMode(t); + switch (autosnap) { case SACTSNAP_STEP: /* frame step */ td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5); td->loc[0] = floor((double)td->loc[0] + 0.5); diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index b55005673d9..f96f2e93bbc 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -42,6 +42,7 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_mode.h" /** Used for NLA transform (stored in #TransData.extra pointer). */ typedef struct TransDataNla { @@ -411,7 +412,8 @@ void recalcData_nla(TransInfo *t) * NOTE: only do this when transform is still running, or we can't restore */ if (t->state != TRANS_CANCEL) { - switch (snla->autosnap) { + const short autosnap = getAnimEdit_SnapMode(t); + switch (autosnap) { case SACTSNAP_FRAME: /* snap to nearest frame */ case SACTSNAP_STEP: /* frame step - this is basically the same, * since we don't have any remapping going on */ -- cgit v1.2.3 From 7f388725337d185a25b8dd3e90d479da86fb7aa1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 18 Aug 2021 00:22:23 +1000 Subject: RNA: de-duplicate enums in generated source Reuse existing enums instead of expanding them since it bloats the binary. The icons enum for example contains over 900 items and was being expanded 17 times (once for each function that takes an icon argument). Similar with the event type enum which contains over 200 items and was duplicated 7 times. makesrna.c now matches enum definitions from declarations in RNA_enum_items.h, using their identifiers when found. The overall space saving on my system is 776kb (tested with a stripped release build). Reviewed By: brecht Ref D12245 --- source/blender/makesrna/RNA_enum_items.h | 240 ++++++++++++++++++++++++++++++ source/blender/makesrna/RNA_enum_types.h | 214 +------------------------- source/blender/makesrna/intern/makesrna.c | 93 ++++++++---- 3 files changed, 309 insertions(+), 238 deletions(-) create mode 100644 source/blender/makesrna/RNA_enum_items.h (limited to 'source/blender') diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h new file mode 100644 index 00000000000..c8f44262020 --- /dev/null +++ b/source/blender/makesrna/RNA_enum_items.h @@ -0,0 +1,240 @@ +/* + * This program is free software you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup RNA + */ + +/* NOTE: this is included multiple times with different #defines for DEF_ENUM. */ + +/* use in cases where only dynamic types are used */ +DEF_ENUM(DummyRNA_NULL_items) +DEF_ENUM(DummyRNA_DEFAULT_items) + +/* all others should follow 'rna_enum_*_items' naming */ +DEF_ENUM(rna_enum_id_type_items) + +DEF_ENUM(rna_enum_object_mode_items) +DEF_ENUM(rna_enum_workspace_object_mode_items) +DEF_ENUM(rna_enum_object_empty_drawtype_items) +DEF_ENUM(rna_enum_object_gpencil_type_items) +DEF_ENUM(rna_enum_metaelem_type_items) + +DEF_ENUM(rna_enum_proportional_falloff_items) +DEF_ENUM(rna_enum_proportional_falloff_curve_only_items) +DEF_ENUM(rna_enum_snap_target_items) +DEF_ENUM(rna_enum_snap_element_items) +DEF_ENUM(rna_enum_snap_node_element_items) +DEF_ENUM(rna_enum_curve_fit_method_items) +DEF_ENUM(rna_enum_mesh_select_mode_items) +DEF_ENUM(rna_enum_mesh_select_mode_uv_items) +DEF_ENUM(rna_enum_mesh_delimit_mode_items) +DEF_ENUM(rna_enum_space_graph_mode_items) +DEF_ENUM(rna_enum_space_file_browse_mode_items) +DEF_ENUM(rna_enum_space_sequencer_view_type_items) +DEF_ENUM(rna_enum_space_type_items) +DEF_ENUM(rna_enum_space_image_mode_items) +DEF_ENUM(rna_enum_space_image_mode_all_items) +DEF_ENUM(rna_enum_space_action_mode_items) +DEF_ENUM(rna_enum_fileselect_params_sort_items) +DEF_ENUM(rna_enum_region_type_items) +DEF_ENUM(rna_enum_object_modifier_type_items) +DEF_ENUM(rna_enum_constraint_type_items) +DEF_ENUM(rna_enum_boidrule_type_items) +DEF_ENUM(rna_enum_sequence_modifier_type_items) +DEF_ENUM(rna_enum_object_greasepencil_modifier_type_items) +DEF_ENUM(rna_enum_object_shaderfx_type_items) + +DEF_ENUM(rna_enum_modifier_triangulate_quad_method_items) +DEF_ENUM(rna_enum_modifier_triangulate_ngon_method_items) +DEF_ENUM(rna_enum_modifier_shrinkwrap_mode_items) + +DEF_ENUM(rna_enum_image_type_items) +DEF_ENUM(rna_enum_image_color_mode_items) +DEF_ENUM(rna_enum_image_color_depth_items) +DEF_ENUM(rna_enum_image_generated_type_items) + +DEF_ENUM(rna_enum_normal_space_items) +DEF_ENUM(rna_enum_normal_swizzle_items) +DEF_ENUM(rna_enum_bake_save_mode_items) +DEF_ENUM(rna_enum_bake_target_items) + +DEF_ENUM(rna_enum_views_format_items) +DEF_ENUM(rna_enum_views_format_multilayer_items) +DEF_ENUM(rna_enum_views_format_multiview_items) +DEF_ENUM(rna_enum_stereo3d_display_items) +DEF_ENUM(rna_enum_stereo3d_anaglyph_type_items) +DEF_ENUM(rna_enum_stereo3d_interlace_type_items) + +#ifdef WITH_OPENEXR +DEF_ENUM(rna_enum_exr_codec_items) +#endif +DEF_ENUM(rna_enum_color_sets_items) + +DEF_ENUM(rna_enum_beztriple_keyframe_type_items) +DEF_ENUM(rna_enum_beztriple_interpolation_mode_items) +DEF_ENUM(rna_enum_beztriple_interpolation_easing_items) +DEF_ENUM(rna_enum_fcurve_auto_smoothing_items) +DEF_ENUM(rna_enum_keyframe_handle_type_items) +DEF_ENUM(rna_enum_driver_target_rotation_mode_items) + +DEF_ENUM(rna_enum_keyingset_path_grouping_items) +DEF_ENUM(rna_enum_keying_flag_items) +DEF_ENUM(rna_enum_keying_flag_items_api) + +DEF_ENUM(rna_enum_fmodifier_type_items) + +DEF_ENUM(rna_enum_motionpath_bake_location_items) + +DEF_ENUM(rna_enum_event_value_all_items) +DEF_ENUM(rna_enum_event_value_keymouse_items) +DEF_ENUM(rna_enum_event_value_tweak_items) + +DEF_ENUM(rna_enum_event_type_items) +DEF_ENUM(rna_enum_event_type_mask_items) + +DEF_ENUM(rna_enum_operator_type_flag_items) +DEF_ENUM(rna_enum_operator_return_items) +DEF_ENUM(rna_enum_operator_property_tags) + +DEF_ENUM(rna_enum_brush_sculpt_tool_items) +DEF_ENUM(rna_enum_brush_uv_sculpt_tool_items) +DEF_ENUM(rna_enum_brush_vertex_tool_items) +DEF_ENUM(rna_enum_brush_weight_tool_items) +DEF_ENUM(rna_enum_brush_gpencil_types_items) +DEF_ENUM(rna_enum_brush_gpencil_vertex_types_items) +DEF_ENUM(rna_enum_brush_gpencil_sculpt_types_items) +DEF_ENUM(rna_enum_brush_gpencil_weight_types_items) +DEF_ENUM(rna_enum_brush_image_tool_items) + +DEF_ENUM(rna_enum_axis_xy_items) +DEF_ENUM(rna_enum_axis_xyz_items) + +DEF_ENUM(rna_enum_axis_flag_xyz_items) + +DEF_ENUM(rna_enum_symmetrize_direction_items) + +DEF_ENUM(rna_enum_texture_type_items) + +DEF_ENUM(rna_enum_light_type_items) + +DEF_ENUM(rna_enum_lightprobes_type_items) + +DEF_ENUM(rna_enum_unpack_method_items) + +DEF_ENUM(rna_enum_object_type_items) +DEF_ENUM(rna_enum_object_rotation_mode_items) + +DEF_ENUM(rna_enum_object_type_curve_items) + +DEF_ENUM(rna_enum_rigidbody_object_type_items) +DEF_ENUM(rna_enum_rigidbody_object_shape_items) +DEF_ENUM(rna_enum_rigidbody_constraint_type_items) + +DEF_ENUM(rna_enum_object_axis_items) + +DEF_ENUM(rna_enum_render_pass_type_items) + +DEF_ENUM(rna_enum_bake_pass_type_items) +DEF_ENUM(rna_enum_bake_pass_filter_type_items) + +DEF_ENUM(rna_enum_keymap_propvalue_items) + +DEF_ENUM(rna_enum_operator_context_items) + +DEF_ENUM(rna_enum_wm_report_items) + +DEF_ENUM(rna_enum_property_type_items) +DEF_ENUM(rna_enum_property_subtype_items) +DEF_ENUM(rna_enum_property_unit_items) + +DEF_ENUM(rna_enum_shading_type_items) + +DEF_ENUM(rna_enum_navigation_mode_items) + +DEF_ENUM(rna_enum_node_socket_in_out_items) + +DEF_ENUM(rna_enum_node_math_items) +DEF_ENUM(rna_enum_mapping_type_items) +DEF_ENUM(rna_enum_node_vec_math_items) +DEF_ENUM(rna_enum_node_boolean_math_items) +DEF_ENUM(rna_enum_node_float_compare_items) +DEF_ENUM(rna_enum_node_filter_items) +DEF_ENUM(rna_enum_node_float_to_int_items) +DEF_ENUM(rna_enum_node_map_range_items) +DEF_ENUM(rna_enum_node_clamp_items) + +DEF_ENUM(rna_enum_ramp_blend_items) + +DEF_ENUM(rna_enum_prop_dynamicpaint_type_items) + +DEF_ENUM(rna_enum_clip_editor_mode_items) + +DEF_ENUM(rna_enum_icon_items) +DEF_ENUM(rna_enum_uilist_layout_type_items) + +DEF_ENUM(rna_enum_linestyle_color_modifier_type_items) +DEF_ENUM(rna_enum_linestyle_alpha_modifier_type_items) +DEF_ENUM(rna_enum_linestyle_thickness_modifier_type_items) +DEF_ENUM(rna_enum_linestyle_geometry_modifier_type_items) + +DEF_ENUM(rna_enum_window_cursor_items) + +DEF_ENUM(rna_enum_dt_method_vertex_items) +DEF_ENUM(rna_enum_dt_method_edge_items) +DEF_ENUM(rna_enum_dt_method_loop_items) +DEF_ENUM(rna_enum_dt_method_poly_items) +DEF_ENUM(rna_enum_dt_mix_mode_items) +DEF_ENUM(rna_enum_dt_layers_select_src_items) +DEF_ENUM(rna_enum_dt_layers_select_dst_items) + +DEF_ENUM(rna_enum_context_mode_items) + +DEF_ENUM(rna_enum_preference_section_items) + +DEF_ENUM(rna_enum_attribute_type_items) +DEF_ENUM(rna_enum_attribute_type_with_auto_items) +DEF_ENUM(rna_enum_attribute_domain_items) +DEF_ENUM(rna_enum_attribute_domain_with_auto_items) + +DEF_ENUM(rna_enum_collection_color_items) + +DEF_ENUM(rna_enum_subdivision_uv_smooth_items) +DEF_ENUM(rna_enum_subdivision_boundary_smooth_items) + +DEF_ENUM(rna_enum_transform_orientation_items) + +/* Not available to RNA pre-processing (`makrsrna`). + * Defined in editors for example. */ +#ifndef RNA_MAKESRNA + +DEF_ENUM(rna_enum_particle_edit_hair_brush_items) +DEF_ENUM(rna_enum_particle_edit_disconnected_hair_brush_items) + +DEF_ENUM(rna_enum_keyframe_paste_offset_items) +DEF_ENUM(rna_enum_keyframe_paste_merge_items) + +DEF_ENUM(rna_enum_transform_pivot_items_full) +DEF_ENUM(rna_enum_transform_mode_types) + +/* In the runtime part of RNA, could be removed from this section. */ +DEF_ENUM(rna_enum_nla_mode_extend_items) +DEF_ENUM(rna_enum_nla_mode_blend_items) +DEF_ENUM(rna_enum_keyblock_type_items) + +#endif + +#undef DEF_ENUM diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 7e3f279b251..d7520834287 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -32,221 +32,11 @@ struct bNodeTreeType; struct bNodeType; /* Types */ +#define DEF_ENUM(id) extern const EnumPropertyItem id[]; +#include "RNA_enum_items.h" -/* use in cases where only dynamic types are used */ -extern const EnumPropertyItem DummyRNA_NULL_items[]; -extern const EnumPropertyItem DummyRNA_DEFAULT_items[]; - -/* all others should follow 'rna_enum_*_items' naming */ -extern const EnumPropertyItem rna_enum_id_type_items[]; - -extern const EnumPropertyItem rna_enum_object_mode_items[]; -extern const EnumPropertyItem rna_enum_workspace_object_mode_items[]; -extern const EnumPropertyItem rna_enum_object_empty_drawtype_items[]; -extern const EnumPropertyItem rna_enum_object_gpencil_type_items[]; -extern const EnumPropertyItem rna_enum_metaelem_type_items[]; - -extern const EnumPropertyItem rna_enum_proportional_falloff_items[]; -extern const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]; -extern const EnumPropertyItem rna_enum_snap_target_items[]; -extern const EnumPropertyItem rna_enum_snap_element_items[]; -extern const EnumPropertyItem rna_enum_snap_node_element_items[]; -extern const EnumPropertyItem rna_enum_curve_fit_method_items[]; -extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; -extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[]; -extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; -extern const EnumPropertyItem rna_enum_space_graph_mode_items[]; -extern const EnumPropertyItem rna_enum_space_file_browse_mode_items[]; -extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[]; -extern const EnumPropertyItem rna_enum_space_type_items[]; -extern const EnumPropertyItem rna_enum_space_image_mode_items[]; -extern const EnumPropertyItem rna_enum_space_image_mode_all_items[]; -extern const EnumPropertyItem rna_enum_space_action_mode_items[]; -extern const EnumPropertyItem rna_enum_fileselect_params_sort_items[]; -extern const EnumPropertyItem rna_enum_region_type_items[]; -extern const EnumPropertyItem rna_enum_object_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_constraint_type_items[]; -extern const EnumPropertyItem rna_enum_boidrule_type_items[]; -extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_object_shaderfx_type_items[]; - -extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]; -extern const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]; -extern const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[]; - -extern const EnumPropertyItem rna_enum_image_type_items[]; -extern const EnumPropertyItem rna_enum_image_color_mode_items[]; -extern const EnumPropertyItem rna_enum_image_color_depth_items[]; -extern const EnumPropertyItem rna_enum_image_generated_type_items[]; - -extern const EnumPropertyItem rna_enum_normal_space_items[]; -extern const EnumPropertyItem rna_enum_normal_swizzle_items[]; -extern const EnumPropertyItem rna_enum_bake_save_mode_items[]; -extern const EnumPropertyItem rna_enum_bake_target_items[]; - -extern const EnumPropertyItem rna_enum_views_format_items[]; -extern const EnumPropertyItem rna_enum_views_format_multilayer_items[]; -extern const EnumPropertyItem rna_enum_views_format_multiview_items[]; -extern const EnumPropertyItem rna_enum_stereo3d_display_items[]; -extern const EnumPropertyItem rna_enum_stereo3d_anaglyph_type_items[]; -extern const EnumPropertyItem rna_enum_stereo3d_interlace_type_items[]; - -extern const EnumPropertyItem rna_enum_exr_codec_items[]; -extern const EnumPropertyItem rna_enum_color_sets_items[]; - -extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[]; -extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]; -extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]; -extern const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[]; -extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[]; -extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[]; - -extern const EnumPropertyItem rna_enum_keyblock_type_items[]; - -extern const EnumPropertyItem rna_enum_keyingset_path_grouping_items[]; -extern const EnumPropertyItem rna_enum_keying_flag_items[]; -extern const EnumPropertyItem rna_enum_keying_flag_items_api[]; - -extern const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]; -extern const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]; - -extern const EnumPropertyItem rna_enum_fmodifier_type_items[]; - -extern const EnumPropertyItem rna_enum_nla_mode_extend_items[]; -extern const EnumPropertyItem rna_enum_nla_mode_blend_items[]; - -extern const EnumPropertyItem rna_enum_motionpath_bake_location_items[]; - -extern const EnumPropertyItem rna_enum_event_value_all_items[]; -extern const EnumPropertyItem rna_enum_event_value_keymouse_items[]; -extern const EnumPropertyItem rna_enum_event_value_tweak_items[]; - -extern const EnumPropertyItem rna_enum_event_type_items[]; -extern const EnumPropertyItem rna_enum_event_type_mask_items[]; - -extern const EnumPropertyItem rna_enum_operator_type_flag_items[]; -extern const EnumPropertyItem rna_enum_operator_return_items[]; -extern const EnumPropertyItem rna_enum_operator_property_tags[]; - -extern const EnumPropertyItem rna_enum_brush_sculpt_tool_items[]; -extern const EnumPropertyItem rna_enum_brush_uv_sculpt_tool_items[]; -extern const EnumPropertyItem rna_enum_brush_vertex_tool_items[]; -extern const EnumPropertyItem rna_enum_brush_weight_tool_items[]; -extern const EnumPropertyItem rna_enum_brush_gpencil_types_items[]; -extern const EnumPropertyItem rna_enum_brush_gpencil_vertex_types_items[]; -extern const EnumPropertyItem rna_enum_brush_gpencil_sculpt_types_items[]; -extern const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[]; -extern const EnumPropertyItem rna_enum_brush_image_tool_items[]; - -extern const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[]; -extern const EnumPropertyItem rna_enum_particle_edit_disconnected_hair_brush_items[]; - -extern const EnumPropertyItem rna_enum_uv_sculpt_tool_items[]; - -extern const EnumPropertyItem rna_enum_axis_xy_items[]; -extern const EnumPropertyItem rna_enum_axis_xyz_items[]; - -extern const EnumPropertyItem rna_enum_axis_flag_xyz_items[]; - -extern const EnumPropertyItem rna_enum_symmetrize_direction_items[]; - -extern const EnumPropertyItem rna_enum_texture_type_items[]; - -extern const EnumPropertyItem rna_enum_light_type_items[]; - -extern const EnumPropertyItem rna_enum_lightprobes_type_items[]; - -extern const EnumPropertyItem rna_enum_unpack_method_items[]; - -extern const EnumPropertyItem rna_enum_object_type_items[]; -extern const EnumPropertyItem rna_enum_object_rotation_mode_items[]; - -extern const EnumPropertyItem rna_enum_object_type_curve_items[]; - -extern const EnumPropertyItem rna_enum_rigidbody_object_type_items[]; -extern const EnumPropertyItem rna_enum_rigidbody_object_shape_items[]; -extern const EnumPropertyItem rna_enum_rigidbody_constraint_type_items[]; - -extern const EnumPropertyItem rna_enum_object_axis_items[]; - -extern const EnumPropertyItem rna_enum_controller_type_items[]; - -extern const EnumPropertyItem rna_enum_render_pass_type_items[]; -extern const EnumPropertyItem rna_enum_render_pass_debug_type_items[]; - -extern const EnumPropertyItem rna_enum_bake_pass_type_items[]; -extern const EnumPropertyItem rna_enum_bake_pass_filter_type_items[]; - -extern const EnumPropertyItem rna_enum_keymap_propvalue_items[]; - -extern const EnumPropertyItem rna_enum_operator_context_items[]; - -extern const EnumPropertyItem rna_enum_wm_report_items[]; - -extern const EnumPropertyItem rna_enum_transform_pivot_items_full[]; -extern const EnumPropertyItem rna_enum_transform_orientation_items[]; -extern const EnumPropertyItem rna_enum_transform_mode_types[]; - -extern const EnumPropertyItem rna_enum_property_type_items[]; -extern const EnumPropertyItem rna_enum_property_subtype_items[]; -extern const EnumPropertyItem rna_enum_property_unit_items[]; - -extern const EnumPropertyItem rna_enum_shading_type_items[]; - -extern const EnumPropertyItem rna_enum_navigation_mode_items[]; - -extern const EnumPropertyItem rna_enum_node_socket_in_out_items[]; - -extern const EnumPropertyItem rna_enum_node_math_items[]; -extern const EnumPropertyItem rna_enum_mapping_type_items[]; -extern const EnumPropertyItem rna_enum_node_vec_math_items[]; -extern const EnumPropertyItem rna_enum_node_boolean_math_items[]; -extern const EnumPropertyItem rna_enum_node_float_compare_items[]; -extern const EnumPropertyItem rna_enum_node_filter_items[]; -extern const EnumPropertyItem rna_enum_node_float_to_int_items[]; -extern const EnumPropertyItem rna_enum_node_map_range_items[]; -extern const EnumPropertyItem rna_enum_node_clamp_items[]; - -extern const EnumPropertyItem rna_enum_ramp_blend_items[]; - -extern const EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[]; - -extern const EnumPropertyItem rna_enum_clip_editor_mode_items[]; - -extern const EnumPropertyItem rna_enum_icon_items[]; -extern const EnumPropertyItem rna_enum_uilist_layout_type_items[]; - -extern const EnumPropertyItem rna_enum_linestyle_color_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_linestyle_alpha_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_linestyle_thickness_modifier_type_items[]; -extern const EnumPropertyItem rna_enum_linestyle_geometry_modifier_type_items[]; - -extern const EnumPropertyItem rna_enum_window_cursor_items[]; - -extern const EnumPropertyItem rna_enum_dt_method_vertex_items[]; -extern const EnumPropertyItem rna_enum_dt_method_edge_items[]; -extern const EnumPropertyItem rna_enum_dt_method_loop_items[]; -extern const EnumPropertyItem rna_enum_dt_method_poly_items[]; -extern const EnumPropertyItem rna_enum_dt_mix_mode_items[]; -extern const EnumPropertyItem rna_enum_dt_layers_select_src_items[]; -extern const EnumPropertyItem rna_enum_dt_layers_select_dst_items[]; - -extern const EnumPropertyItem rna_enum_context_mode_items[]; - -extern const EnumPropertyItem rna_enum_curveprofile_preset_items[]; -extern const EnumPropertyItem rna_enum_preference_section_items[]; - -extern const EnumPropertyItem rna_enum_attribute_type_items[]; -extern const EnumPropertyItem rna_enum_attribute_type_with_auto_items[]; -extern const EnumPropertyItem rna_enum_attribute_domain_items[]; -extern const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[]; extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bool *r_free); -extern const EnumPropertyItem rna_enum_collection_color_items[]; - -extern const EnumPropertyItem rna_enum_subdivision_uv_smooth_items[]; -extern const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[]; /** * For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64 * bit integers. So can't use the regular #EnumPropertyItem. Would be nice if RNA supported this diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 719b0f73a9d..36f19907080 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -582,6 +582,23 @@ static int rna_color_quantize(PropertyRNA *prop, PropertyDefRNA *dp) (IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0)); } +/** + * Return the identifier for an enum which is defined in "RNA_enum_items.h". + * + * Prevents expanding duplicate enums bloating the binary size. + */ +static const char *rna_enum_id_from_pointer(const EnumPropertyItem *item) +{ +#define RNA_MAKESRNA +#define DEF_ENUM(id) \ + if (item == id) { \ + return STRINGIFY(id); \ + } +#include "RNA_enum_items.h" +#undef RNA_MAKESRNA + return NULL; +} + static const char *rna_function_string(const void *func) { return (func) ? (const char *)func : "NULL"; @@ -3675,37 +3692,55 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr int i, defaultfound = 0, totflag = 0; if (eprop->item) { - fprintf(f, - "static const EnumPropertyItem rna_%s%s_%s_items[%d] = {\n\t", - srna->identifier, - strnest, - prop->identifier, - eprop->totitem + 1); - - for (i = 0; i < eprop->totitem; i++) { - fprintf(f, "{%d, ", eprop->item[i].value); - rna_print_c_string(f, eprop->item[i].identifier); - fprintf(f, ", "); - fprintf(f, "%d, ", eprop->item[i].icon); - rna_print_c_string(f, eprop->item[i].name); - fprintf(f, ", "); - rna_print_c_string(f, eprop->item[i].description); - fprintf(f, "},\n\t"); - - if (eprop->item[i].identifier[0]) { - if (prop->flag & PROP_ENUM_FLAG) { - totflag |= eprop->item[i].value; + /* Inline the enum if this is not a defined in "RNA_enum_items.h". */ + const char *item_global_id = rna_enum_id_from_pointer(eprop->item); + if (item_global_id == NULL) { + fprintf(f, + "static const EnumPropertyItem rna_%s%s_%s_items[%d] = {\n\t", + srna->identifier, + strnest, + prop->identifier, + eprop->totitem + 1); + + for (i = 0; i < eprop->totitem; i++) { + fprintf(f, "{%d, ", eprop->item[i].value); + rna_print_c_string(f, eprop->item[i].identifier); + fprintf(f, ", "); + fprintf(f, "%d, ", eprop->item[i].icon); + rna_print_c_string(f, eprop->item[i].name); + fprintf(f, ", "); + rna_print_c_string(f, eprop->item[i].description); + fprintf(f, "},\n\t"); + + if (eprop->item[i].identifier[0]) { + if (prop->flag & PROP_ENUM_FLAG) { + totflag |= eprop->item[i].value; + } + else { + if (eprop->defaultvalue == eprop->item[i].value) { + defaultfound = 1; + } + } } - else { - if (eprop->defaultvalue == eprop->item[i].value) { - defaultfound = 1; + } + + fprintf(f, "{0, NULL, 0, NULL, NULL}\n};\n\n"); + } + else { + for (i = 0; i < eprop->totitem; i++) { + if (eprop->item[i].identifier[0]) { + if (prop->flag & PROP_ENUM_FLAG) { + totflag |= eprop->item[i].value; + } + else { + if (eprop->defaultvalue == eprop->item[i].value) { + defaultfound = 1; + } } } } } - fprintf(f, "{0, NULL, 0, NULL, NULL}\n};\n\n"); - if (prop->flag & PROP_ENUM_FLAG) { if (eprop->defaultvalue & ~totflag) { CLOG_ERROR(&LOG, @@ -4047,7 +4082,13 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr rna_function_string(eprop->get_ex), rna_function_string(eprop->set_ex)); if (eprop->item) { - fprintf(f, "rna_%s%s_%s_items, ", srna->identifier, strnest, prop->identifier); + const char *item_global_id = rna_enum_id_from_pointer(eprop->item); + if (item_global_id != NULL) { + fprintf(f, "%s, ", item_global_id); + } + else { + fprintf(f, "rna_%s%s_%s_items, ", srna->identifier, strnest, prop->identifier); + } } else { fprintf(f, "NULL, "); -- cgit v1.2.3 From e98824d6c44d02a9f0223f5406112725899276c3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 18 Aug 2021 00:37:04 +1000 Subject: CMake: add missing headers --- source/blender/editors/util/CMakeLists.txt | 1 + source/blender/makesrna/intern/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 54ec6b22e70..b396e348845 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC ../include/ED_info.h ../include/ED_keyframes_draw.h ../include/ED_keyframes_edit.h + ../include/ED_keyframes_keylist.h ../include/ED_keyframing.h ../include/ED_lattice.h ../include/ED_markers.h diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 95b7b7e5406..7e6d0aea2ee 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -175,6 +175,7 @@ set(SRC_RNA_INC ../RNA_access.h ../RNA_define.h ../RNA_documentation.h + ../RNA_enum_items.h ../RNA_enum_types.h ../RNA_types.h ) -- cgit v1.2.3 From 88dc274d0533e3b4427a61718958bf84367b5077 Mon Sep 17 00:00:00 2001 From: Henrik Dick Date: Tue, 17 Aug 2021 20:04:27 +0200 Subject: GPencil: Convert from Mesh copying Vertex Groups This patch adds the missing ability to keep the vertex groups when converting to a grease pencil object. This is increadible useful to create rigged grease pencil objects which move together with rigged meshes. Differential Revision: https://developer.blender.org/D12249 --- source/blender/blenkernel/BKE_gpencil_geom.h | 3 +- source/blender/blenkernel/intern/gpencil_geom.cc | 210 +++++++++++++---------- source/blender/editors/gpencil/gpencil_mesh.c | 3 +- source/blender/editors/object/object_add.c | 3 +- 4 files changed, 126 insertions(+), 93 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index c1ccae7a437..29e3a74b1b2 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -169,7 +169,8 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain, const float matrix[4][4], const int frame_offset, const bool use_seams, - const bool use_faces); + const bool use_faces, + const bool use_vgroups); void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd, struct bGPDstroke *gps, diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index f8a07939096..f2042d3098c 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -2269,7 +2269,8 @@ static void gpencil_generate_edgeloops(Object *ob, const int thickness, const float offset, const float matrix[4][4], - const bool use_seams) + const bool use_seams, + const bool use_vgroups) { Mesh *me = (Mesh *)ob->data; if (me->totedge == 0) { @@ -2278,9 +2279,9 @@ static void gpencil_generate_edgeloops(Object *ob, /* Arrays for all edge vertices (forward and backward) that form a edge loop. * This is reused for each edge-loop to create gpencil stroke. */ - uint *stroke = (uint *)MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); - uint *stroke_fw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); - uint *stroke_bw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); + uint *stroke = (uint *)MEM_mallocN(sizeof(uint) * me->totedge * 2, __func__); + uint *stroke_fw = (uint *)MEM_mallocN(sizeof(uint) * me->totedge, __func__); + uint *stroke_bw = (uint *)MEM_mallocN(sizeof(uint) * me->totedge, __func__); /* Create array with all edges. */ GpEdge *gp_edges = (GpEdge *)MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); @@ -2311,11 +2312,6 @@ static void gpencil_generate_edgeloops(Object *ob, bool pending = true; int e = 0; while (pending) { - /* Clear arrays of stroke. */ - memset(stroke_fw, 0, sizeof(uint) * me->totedge); - memset(stroke_bw, 0, sizeof(uint) * me->totedge); - memset(stroke, 0, sizeof(uint) * me->totedge * 2); - gped = &gp_edges[e]; /* Look first unused edge. */ if (gped->flag != 0) { @@ -2330,7 +2326,7 @@ static void gpencil_generate_edgeloops(Object *ob, stroke_bw[0] = e; gped->flag = 1; - /* Hash used to avoid loop over same vertice. */ + /* Hash used to avoid loop over same vertices. */ GHash *v_table = BLI_ghash_int_new(__func__); /* Look forward edges. */ int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, angle, false); @@ -2354,38 +2350,41 @@ static void gpencil_generate_edgeloops(Object *ob, bGPDstroke *gps_stroke = BKE_gpencil_stroke_add( gpf_stroke, MAX2(stroke_mat_index, 0), array_len + 1, thickness * thickness, false); + /* Create dvert data. */ + MDeformVert *me_dvert = me->dvert; + if (use_vgroups && me_dvert) { + gps_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * (array_len + 1), + "gp_stroke_dverts"); + } + /* Create first segment. */ float fpt[3]; - uint v = stroke[0]; - gped = &gp_edges[v]; - bGPDspoint *pt = &gps_stroke->points[0]; - mul_v3_v3fl(fpt, gped->n1, offset); - add_v3_v3v3(&pt->x, gped->v1_co, fpt); - mul_m4_v3(matrix, &pt->x); - - pt->pressure = 1.0f; - pt->strength = 1.0f; - - pt = &gps_stroke->points[1]; - mul_v3_v3fl(fpt, gped->n2, offset); - add_v3_v3v3(&pt->x, gped->v2_co, fpt); - mul_m4_v3(matrix, &pt->x); - - pt->pressure = 1.0f; - pt->strength = 1.0f; - - /* Add next segments. */ - for (int i = 1; i < array_len; i++) { - v = stroke[i]; - gped = &gp_edges[v]; - - pt = &gps_stroke->points[i + 1]; - mul_v3_v3fl(fpt, gped->n2, offset); - add_v3_v3v3(&pt->x, gped->v2_co, fpt); + for (int i = 0; i < array_len + 1; i++) { + int vertex_index = i == 0 ? gp_edges[stroke[0]].v1 : gp_edges[stroke[i - 1]].v2; + MVert *mv = &me->mvert[vertex_index]; + + /* Add segment. */ + bGPDspoint *pt = &gps_stroke->points[i]; + normal_short_to_float_v3(fpt, mv->no); + mul_v3_v3fl(fpt, fpt, offset); + add_v3_v3v3(&pt->x, mv->co, fpt); mul_m4_v3(matrix, &pt->x); pt->pressure = 1.0f; pt->strength = 1.0f; + + /* Copy vertex groups from mesh. Assuming they already exist in the same order. */ + if (use_vgroups && me_dvert) { + MDeformVert *dv = &gps_stroke->dvert[i]; + MDeformVert *src_dv = &me_dvert[vertex_index]; + dv->totweight = src_dv->totweight; + dv->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_stroke_dverts_dw"); + for (int j = 0; j < dv->totweight; j++) { + dv->dw[j].weight = src_dv->dw[j].weight; + dv->dw[j].def_nr = src_dv->dw[j].def_nr; + } + } } BKE_gpencil_stroke_geometry_update(gpd, gps_stroke); @@ -2488,7 +2487,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain, const float matrix[4][4], const int frame_offset, const bool use_seams, - const bool use_faces) + const bool use_faces, + const bool use_vgroups) { if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { return false; @@ -2505,83 +2505,105 @@ bool BKE_gpencil_convert_mesh(Main *bmain, char element_name[200]; /* Need at least an edge. */ - if (me_eval->totvert < 2) { + if (me_eval->totedge < 1) { return false; } + /* Create matching vertex groups. */ + BKE_defgroup_copy_list(&gpd->vertex_group_names, &me_eval->vertex_group_names); + gpd->vertex_group_active_index = me_eval->vertex_group_active_index; + const float default_colors[2][4] = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}; - /* Create stroke material. */ + /* Lookup existing stroke material on gp object. */ make_element_name(ob_mesh->id.name + 2, "Stroke", 64, element_name); int stroke_mat_index = gpencil_material_find_index_by_name(ob_gp, element_name); if (stroke_mat_index == -1) { + /* Create new default stroke material as there is no existing material. */ gpencil_add_material( bmain, ob_gp, element_name, default_colors[0], true, false, &stroke_mat_index); } /* Export faces as filled strokes. */ - if (use_faces) { - + if (use_faces && mpoly_len > 0) { /* Read all polygons and create fill for each. */ - if (mpoly_len > 0) { - make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); - /* Create Layer and Frame. */ - bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); - if (gpl_fill == nullptr) { - gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); - } - bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( - gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); - int i; - for (i = 0; i < mpoly_len; i++) { - const MPoly *mp = &mpoly[i]; - - /* Find material. */ - int mat_idx = 0; - Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); - make_element_name( - ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); - mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); - if (mat_idx == -1) { - float color[4]; - if (ma != nullptr) { - copy_v3_v3(color, &ma->r); - color[3] = 1.0f; - } - else { - copy_v4_v4(color, default_colors[1]); - } - gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); + make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); + /* Create Layer and Frame. */ + bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); + if (gpl_fill == nullptr) { + gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); + } + bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( + gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); + int i; + for (i = 0; i < mpoly_len; i++) { + const MPoly *mp = &mpoly[i]; + + /* Find material. */ + int mat_idx = 0; + Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); + make_element_name( + ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); + mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); + if (mat_idx == -1) { + float color[4]; + if (ma != nullptr) { + copy_v3_v3(color, &ma->r); + color[3] = 1.0f; } + else { + copy_v4_v4(color, default_colors[1]); + } + gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); + } - bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, mat_idx, mp->totloop, 10, false); - gps_fill->flag |= GP_STROKE_CYCLIC; + bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, mat_idx, mp->totloop, 10, false); + gps_fill->flag |= GP_STROKE_CYCLIC; - /* Add points to strokes. */ - for (int j = 0; j < mp->totloop; j++) { - const MLoop *ml = &mloop[mp->loopstart + j]; - const MVert *mv = &me_eval->mvert[ml->v]; + /* Create dvert data. */ + MDeformVert *me_dvert = me_eval->dvert; + if (use_vgroups && me_dvert) { + gps_fill->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * mp->totloop, + "gp_fill_dverts"); + } - bGPDspoint *pt = &gps_fill->points[j]; - copy_v3_v3(&pt->x, mv->co); - mul_m4_v3(matrix, &pt->x); - pt->pressure = 1.0f; - pt->strength = 1.0f; - } - /* If has only 3 points subdivide. */ - if (mp->totloop == 3) { - BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE); + /* Add points to strokes. */ + for (int j = 0; j < mp->totloop; j++) { + const MLoop *ml = &mloop[mp->loopstart + j]; + const MVert *mv = &me_eval->mvert[ml->v]; + + bGPDspoint *pt = &gps_fill->points[j]; + copy_v3_v3(&pt->x, mv->co); + mul_m4_v3(matrix, &pt->x); + pt->pressure = 1.0f; + pt->strength = 1.0f; + + /* Copy vertex groups from mesh. Assuming they already exist in the same order. */ + if (use_vgroups && me_dvert) { + MDeformVert *dv = &gps_fill->dvert[j]; + MDeformVert *src_dv = &me_dvert[ml->v]; + dv->totweight = src_dv->totweight; + dv->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_fill_dverts_dw"); + for (int k = 0; k < dv->totweight; k++) { + dv->dw[k].weight = src_dv->dw[k].weight; + dv->dw[k].def_nr = src_dv->dw[k].def_nr; + } } - - BKE_gpencil_stroke_geometry_update(gpd, gps_fill); } + /* If has only 3 points subdivide. */ + if (mp->totloop == 3) { + BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE); + } + + BKE_gpencil_stroke_geometry_update(gpd, gps_fill); } } /* Create stroke from edges. */ - make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); /* Create Layer and Frame. */ + make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name); if (gpl_stroke == nullptr) { gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false); @@ -2589,8 +2611,16 @@ bool BKE_gpencil_convert_mesh(Main *bmain, bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); - gpencil_generate_edgeloops( - ob_eval, gpd, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams); + gpencil_generate_edgeloops(ob_eval, + gpd, + gpf_stroke, + stroke_mat_index, + angle, + thickness, + offset, + matrix, + use_seams, + use_vgroups); /* Tag for recalculation */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index 1882285a230..0939d53736b 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -316,7 +316,8 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) ob_eval->obmat, frame_offset, use_seams, - use_faces); + use_faces, + true); /* Reproject all un-tagged created strokes. */ if (project_type != GP_REPROJECT_KEEP) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f98f3242163..12b52907057 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2844,7 +2844,8 @@ static int object_convert_exec(bContext *C, wmOperator *op) matrix, 0, use_seams, - use_faces); + use_faces, + true); /* Remove unused materials. */ int actcol = ob_gpencil->actcol; -- cgit v1.2.3 From e3098de2a1fedd98d9f31d3cb562116f0945b7f9 Mon Sep 17 00:00:00 2001 From: Henrik Dick Date: Tue, 17 Aug 2021 22:16:16 +0200 Subject: GPencil: Fix unreported switch direction not flipping weights There was an unreported bug that switch direction would not switch the order of the vertex group weights. This caused join to do it wrong as well. Changed to use `BLI_array_reverse` function here to reverse both the normal points and the weights, therefore simplifying the code. Differential Revision: https://developer.blender.org/D12251 --- source/blender/blenkernel/intern/gpencil_geom.cc | 45 ++++-------------------- 1 file changed, 6 insertions(+), 39 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index f2042d3098c..0f218d6166c 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.h" #include "BLI_blenlib.h" #include "BLI_float3.hh" #include "BLI_ghash.h" @@ -2817,46 +2818,12 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps) /* Flip stroke. */ void BKE_gpencil_stroke_flip(bGPDstroke *gps) { - int end = gps->totpoints - 1; + /* Reverse points. */ + BLI_array_reverse(gps->points, gps->totpoints); - for (int i = 0; i < gps->totpoints / 2; i++) { - bGPDspoint *point, *point2; - bGPDspoint pt; - - /* save first point */ - point = &gps->points[i]; - pt.x = point->x; - pt.y = point->y; - pt.z = point->z; - pt.flag = point->flag; - pt.pressure = point->pressure; - pt.strength = point->strength; - pt.time = point->time; - copy_v4_v4(pt.vert_color, point->vert_color); - - /* replace first point with last point */ - point2 = &gps->points[end]; - point->x = point2->x; - point->y = point2->y; - point->z = point2->z; - point->flag = point2->flag; - point->pressure = point2->pressure; - point->strength = point2->strength; - point->time = point2->time; - copy_v4_v4(point->vert_color, point2->vert_color); - - /* replace last point with first saved before */ - point = &gps->points[end]; - point->x = pt.x; - point->y = pt.y; - point->z = pt.z; - point->flag = pt.flag; - point->pressure = pt.pressure; - point->strength = pt.strength; - point->time = pt.time; - copy_v4_v4(point->vert_color, pt.vert_color); - - end--; + /* Reverse vertex groups if available. */ + if (gps->dvert) { + BLI_array_reverse(gps->dvert, gps->totpoints); } } -- cgit v1.2.3 From 809dce5bdeeb193a160b2961bf069eab76c2ce01 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 17 Aug 2021 16:53:29 -0300 Subject: Cleanup: move 'recalcData' to 'transform_convert.h' The `recalcData` function is defined in `transform_convert.c`, so the header is most expected to be `transform_convert.h`. --- source/blender/editors/transform/transform.h | 1 - source/blender/editors/transform/transform_convert.h | 1 + source/blender/editors/transform/transform_generics.c | 1 + source/blender/editors/transform/transform_mode_align.c | 2 ++ source/blender/editors/transform/transform_mode_baketime.c | 4 +++- source/blender/editors/transform/transform_mode_bbone_resize.c | 4 +++- source/blender/editors/transform/transform_mode_bend.c | 4 +++- source/blender/editors/transform/transform_mode_boneenvelope.c | 4 +++- source/blender/editors/transform/transform_mode_boneroll.c | 4 +++- source/blender/editors/transform/transform_mode_curveshrinkfatten.c | 4 +++- source/blender/editors/transform/transform_mode_edge_bevelweight.c | 4 +++- source/blender/editors/transform/transform_mode_edge_crease.c | 4 +++- source/blender/editors/transform/transform_mode_edge_rotate_normal.c | 3 ++- source/blender/editors/transform/transform_mode_gpopacity.c | 4 +++- source/blender/editors/transform/transform_mode_gpshrinkfatten.c | 4 +++- source/blender/editors/transform/transform_mode_maskshrinkfatten.c | 4 +++- source/blender/editors/transform/transform_mode_mirror.c | 2 ++ source/blender/editors/transform/transform_mode_push_pull.c | 4 +++- source/blender/editors/transform/transform_mode_rotate.c | 4 +++- source/blender/editors/transform/transform_mode_shear.c | 4 +++- source/blender/editors/transform/transform_mode_shrink_fatten.c | 4 +++- source/blender/editors/transform/transform_mode_skin_resize.c | 4 +++- source/blender/editors/transform/transform_mode_tilt.c | 4 +++- source/blender/editors/transform/transform_mode_timescale.c | 1 + source/blender/editors/transform/transform_mode_timeslide.c | 2 ++ source/blender/editors/transform/transform_mode_timetranslate.c | 4 +++- source/blender/editors/transform/transform_mode_tosphere.c | 4 +++- source/blender/editors/transform/transform_mode_trackball.c | 4 +++- 28 files changed, 71 insertions(+), 22 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 1fa123e8507..549ad770ac6 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -779,7 +779,6 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis void applyTransObjects(TransInfo *t); void restoreTransObjects(TransInfo *t); -void recalcData(TransInfo *t); void calculateCenter2D(TransInfo *t); void calculateCenterLocal(TransInfo *t, const float center_global[3]); diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 971c23b8c69..55731bfa321 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -43,6 +43,7 @@ void sort_trans_data_dist(TransInfo *t); void createTransData(struct bContext *C, TransInfo *t); bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); +void recalcData(TransInfo *t); /* transform_convert_mesh.c */ void transform_convert_mesh_customdatacorrect_init(TransInfo *t); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index be8e551a1e8..81fc1496b1a 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -60,6 +60,7 @@ #include "UI_view2d.h" #include "transform.h" +#include "transform_convert.h" #include "transform_mode.h" #include "transform_orientations.h" #include "transform_snap.h" diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c index 5bc2aa68443..1a1d84699f4 100644 --- a/source/blender/editors/transform/transform_mode_align.c +++ b/source/blender/editors/transform/transform_mode_align.c @@ -32,6 +32,8 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_convert.h" + #include "transform_mode.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c index 5efed6920dc..653944b56a7 100644 --- a/source/blender/editors/transform/transform_mode_baketime.c +++ b/source/blender/editors/transform/transform_mode_baketime.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Bake-Time) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c index e827e604327..95e2d944b9b 100644 --- a/source/blender/editors/transform/transform_mode_bbone_resize.c +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -37,9 +37,11 @@ #include "transform.h" #include "transform_constraints.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (EditBone B-Bone width scaling) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c index 850d26571cd..6d84c397fa6 100644 --- a/source/blender/editors/transform/transform_mode_bend.c +++ b/source/blender/editors/transform/transform_mode_bend.c @@ -44,9 +44,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Bend) Custom Data * \{ */ diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c index ced159a76c9..da7393ab42e 100644 --- a/source/blender/editors/transform/transform_mode_boneenvelope.c +++ b/source/blender/editors/transform/transform_mode_boneenvelope.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Bone Envelope) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c index da6c0b44c3a..cd04ca2b844 100644 --- a/source/blender/editors/transform/transform_mode_boneroll.c +++ b/source/blender/editors/transform/transform_mode_boneroll.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (EditBone Roll) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index 68416c780ef..9433502ef55 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Curve Shrink/Fatten) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c index 425bfec241e..5466ba3e91f 100644 --- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c +++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c @@ -37,9 +37,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Bevel Weight) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index 91e2507e544..1d3b4dbb4f0 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -37,9 +37,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Crease) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index 6f2bcc148ce..1f57bacf78f 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -35,9 +35,10 @@ #include "UI_interface.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" /* -------------------------------------------------------------------- */ /** \name Transform (Normal Rotation) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c index 7c496d271ef..748769491f1 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.c +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -38,9 +38,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (GPencil Strokes Opacity) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c index 608a49f38b1..bc081edd597 100644 --- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -38,9 +38,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (GPencil Strokes Shrink/Fatten) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c index cfbd6030788..327a639773c 100644 --- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Mask Shrink/Fatten) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index f225f1a7c06..2ae32f3545a 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -37,6 +37,8 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_convert.h" + #include "transform_mode.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c index 0492ec8df8c..0527d1bc08e 100644 --- a/source/blender/editors/transform/transform_mode_push_pull.c +++ b/source/blender/editors/transform/transform_mode_push_pull.c @@ -38,9 +38,11 @@ #include "transform.h" #include "transform_constraints.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Push/Pull) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 44a29cfac45..bfbdaa389f4 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -34,9 +34,11 @@ #include "UI_interface.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Rotation) Matrix Cache * \{ */ diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index f5672887905..018725ec6dd 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -41,9 +41,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Shear) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index 4cdaab599b4..b96b8103392 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -40,9 +40,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Shrink-Fatten) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c index 0a7eea8a989..236c9024201 100644 --- a/source/blender/editors/transform/transform_mode_skin_resize.c +++ b/source/blender/editors/transform/transform_mode_skin_resize.c @@ -35,9 +35,11 @@ #include "transform.h" #include "transform_constraints.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Skin) Element * \{ */ diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c index d3b72fdf503..b48f474e16e 100644 --- a/source/blender/editors/transform/transform_mode_tilt.c +++ b/source/blender/editors/transform/transform_mode_tilt.c @@ -36,9 +36,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Tilt) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c index 7ae97c66660..98ffc0abbd4 100644 --- a/source/blender/editors/transform/transform_mode_timescale.c +++ b/source/blender/editors/transform/transform_mode_timescale.c @@ -39,6 +39,7 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_convert.h" #include "transform_mode.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c index 34d3251f9cf..5cc53eb08ce 100644 --- a/source/blender/editors/transform/transform_mode_timeslide.c +++ b/source/blender/editors/transform/transform_mode_timeslide.c @@ -42,6 +42,8 @@ #include "BLT_translation.h" #include "transform.h" +#include "transform_convert.h" + #include "transform_mode.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c index 948242e547f..01b9a08cf27 100644 --- a/source/blender/editors/transform/transform_mode_timetranslate.c +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -39,9 +39,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Animation Translation) * \{ */ diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c index 8587d5ae140..bfc85b2fe44 100644 --- a/source/blender/editors/transform/transform_mode_tosphere.c +++ b/source/blender/editors/transform/transform_mode_tosphere.c @@ -39,9 +39,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name To Sphere Utilities * \{ */ diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c index 68177c6becf..aa8b0783d0a 100644 --- a/source/blender/editors/transform/transform_mode_trackball.c +++ b/source/blender/editors/transform/transform_mode_trackball.c @@ -37,9 +37,11 @@ #include "BLT_translation.h" #include "transform.h" -#include "transform_mode.h" +#include "transform_convert.h" #include "transform_snap.h" +#include "transform_mode.h" + /* -------------------------------------------------------------------- */ /** \name Transform (Rotation - Trackball) Element * \{ */ -- cgit v1.2.3 From 24c16f54571fe948aa5c02f807ca23188b436764 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 17 Aug 2021 00:37:46 +0200 Subject: Fix wireframe overlay not blending over paint overlay correctly When using wireframe opacity, the paint overlay needs to be drawn before the wireframes in order to alpha blend correctly. Sculpt overlays were also affected by this, so this commit refactors this part of the code in case other overlays needs to be added in the future. Reviewed By: Mets Differential Revision: https://developer.blender.org/D12235 --- .../blender/draw/engines/overlay/overlay_engine.c | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 235104245cc..b07e86000fd 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -576,9 +576,20 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_extra_blend_draw(vedata); OVERLAY_volume_draw(vedata); - if (pd->ctx_mode == CTX_MODE_SCULPT) { - /* Sculpt overlays are drawn here to avoid artifacts with wireframe opacity. */ - OVERLAY_sculpt_draw(vedata); + /* These overlays are drawn here to avoid artifacts with wireframe opacity. */ + switch (pd->ctx_mode) { + case CTX_MODE_SCULPT: + OVERLAY_sculpt_draw(vedata); + break; + case CTX_MODE_EDIT_MESH: + case CTX_MODE_POSE: + case CTX_MODE_PAINT_WEIGHT: + case CTX_MODE_PAINT_VERTEX: + case CTX_MODE_PAINT_TEXTURE: + OVERLAY_paint_draw(vedata); + break; + default: + break; } if (DRW_state_is_fbo()) { @@ -601,11 +612,6 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_xray_depth_infront_copy(vedata); - if (pd->ctx_mode == CTX_MODE_PAINT_WEIGHT) { - /* Fix weird case where weightpaint mode needs to draw before xray bones. */ - OVERLAY_paint_draw(vedata); - } - if (DRW_state_is_fbo()) { GPU_framebuffer_bind(fbl->overlay_in_front_fb); } @@ -640,7 +646,6 @@ static void OVERLAY_draw_scene(void *vedata) switch (pd->ctx_mode) { case CTX_MODE_EDIT_MESH: - OVERLAY_paint_draw(vedata); OVERLAY_edit_mesh_draw(vedata); break; case CTX_MODE_EDIT_SURFACE: @@ -654,13 +659,8 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_edit_lattice_draw(vedata); break; case CTX_MODE_POSE: - OVERLAY_paint_draw(vedata); OVERLAY_pose_draw(vedata); break; - case CTX_MODE_PAINT_VERTEX: - case CTX_MODE_PAINT_TEXTURE: - OVERLAY_paint_draw(vedata); - break; case CTX_MODE_PARTICLE: OVERLAY_edit_particle_draw(vedata); break; -- cgit v1.2.3 From f41beca97787d017a437a63cc0da2ce991522dea Mon Sep 17 00:00:00 2001 From: YimingWu Date: Wed, 18 Aug 2021 12:02:32 +0800 Subject: Fix T90695: Lower tile splitting limit for lineart Lowers tile splitting limit so models with extremely dense mesh portions could still have reasonable performance while for more common cases the performance impact should be minimal. Reviewed By: Sebastian Parborg (zeddb), Antonio Vazquez (antoniov) Differential Revision: https://developer.blender.org/D12236 --- source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 9ac07b9632d..4b71011b99a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -208,7 +208,7 @@ typedef struct LineartChainRegisterEntry { enum eLineArtTileRecursiveLimit { /* If tile gets this small, it's already much smaller than a pixel. No need to continue * splitting. */ - LRT_TILE_RECURSIVE_PERSPECTIVE = 30, + LRT_TILE_RECURSIVE_PERSPECTIVE = 16, /* This is a tried-and-true safe value for high poly models that also needed ortho rendering. */ LRT_TILE_RECURSIVE_ORTHO = 10, }; -- cgit v1.2.3 From 400cb25fc77a4131033f69cf328a31cdcf81edb5 Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Tue, 17 Aug 2021 21:42:28 -0700 Subject: UDIM: Support tile sets that do not start at 1001 Removes the artificial requirement that UDIM tile sets start at 1001. Blender was already capable of handling sparse tile sets (non-contiguous tiles) so the restriction around starting at 1001 was unnecessary in general. This required fixing a few UDIM-related python bugs around manually updating the `tile_number` field on images as well. See the differential for details. No script changes are necessary but they will now work, correctly, in many more cases. Differential Revision: https://developer.blender.org/D11859 --- source/blender/blenkernel/BKE_image.h | 2 + source/blender/blenkernel/intern/image.c | 87 ++++++++++++++++++---- source/blender/blenkernel/intern/image_gpu.c | 3 +- source/blender/blenkernel/intern/image_save.c | 18 +++-- source/blender/editors/space_image/image_ops.c | 32 +++++--- .../blender/editors/space_image/image_sequence.c | 34 +++++---- source/blender/makesrna/intern/rna_image.c | 9 +-- 7 files changed, 130 insertions(+), 55 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index ac73bd2b595..3cab1a6b755 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -308,6 +308,8 @@ void BKE_image_get_tile_label(struct Image *ima, struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label); bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile); +void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number); +void BKE_image_sort_tiles(struct Image *ima); bool BKE_image_fill_tile(struct Image *ima, struct ImageTile *tile, diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ba54858ba84..d2ab54de697 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -670,24 +670,27 @@ bool BKE_image_has_opengl_texture(Image *ima) return false; } +static int image_get_tile_number_from_iuser(Image *ima, const ImageUser *iuser) +{ + BLI_assert(ima != NULL && ima->tiles.first); + ImageTile *tile = ima->tiles.first; + return (iuser && iuser->tile) ? iuser->tile : tile->tile_number; +} + ImageTile *BKE_image_get_tile(Image *ima, int tile_number) { if (ima == NULL) { return NULL; } - /* Verify valid tile range. */ - if ((tile_number != 0) && (tile_number < 1001 || tile_number > IMA_UDIM_MAX)) { - return NULL; - } - - /* Tile number 0 is a special case and refers to the first tile, typically + /* Tiles 0 and 1001 are a special case and refer to the first tile, typically * coming from non-UDIM-aware code. */ if (ELEM(tile_number, 0, 1001)) { return ima->tiles.first; } - if (ima->source != IMA_SRC_TILED) { + /* Must have a tiled image and a valid tile number at this point. */ + if (ima->source != IMA_SRC_TILED || tile_number < 1001 || tile_number > IMA_UDIM_MAX) { return NULL; } @@ -702,7 +705,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number) ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser) { - return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001); + return BKE_image_get_tile(ima, image_get_tile_number_from_iuser(ima, iuser)); } int BKE_image_get_tile_from_pos(struct Image *ima, @@ -3803,8 +3806,8 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return false; } - if (tile == ima->tiles.first) { - /* Can't remove first tile. */ + if (BLI_listbase_is_single(&ima->tiles)) { + /* Can't remove the last remaining tile. */ return false; } @@ -3815,6 +3818,64 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return true; } +void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_number) +{ + if (ima == NULL || tile == NULL || ima->source != IMA_SRC_TILED) { + return; + } + + if (new_tile_number < 1001 || new_tile_number > IMA_UDIM_MAX) { + return; + } + + const int old_tile_number = tile->tile_number; + tile->tile_number = new_tile_number; + + if (BKE_image_is_multiview(ima)) { + const int totviews = BLI_listbase_count(&ima->views); + for (int i = 0; i < totviews; i++) { + ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, old_tile_number); + image_remove_ibuf(ima, i, old_tile_number); + image_assign_ibuf(ima, ibuf, i, new_tile_number); + IMB_freeImBuf(ibuf); + } + } + else { + ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, 0, old_tile_number); + image_remove_ibuf(ima, 0, old_tile_number); + image_assign_ibuf(ima, ibuf, 0, new_tile_number); + IMB_freeImBuf(ibuf); + } + + for (int eye = 0; eye < 2; eye++) { + /* Reallocate GPU tile array. */ + if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]); + ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL; + } + if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]); + ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL; + } + } +} + +static int tile_sort_cb(const void *a, const void *b) +{ + const ImageTile *tile_a = a; + const ImageTile *tile_b = b; + return (tile_a->tile_number > tile_b->tile_number) ? 1 : 0; +} + +void BKE_image_sort_tiles(struct Image *ima) +{ + if (ima == NULL || ima->source != IMA_SRC_TILED) { + return; + } + + BLI_listbase_sort(&ima->tiles, tile_sort_cb); +} + bool BKE_image_fill_tile(struct Image *ima, ImageTile *tile, int width, @@ -4890,7 +4951,7 @@ static void image_get_entry_and_index(Image *ima, ImageUser *iuser, int *r_entry } } else if (ima->source == IMA_SRC_TILED) { - frame = (iuser && iuser->tile) ? iuser->tile : 1001; + frame = image_get_tile_number_from_iuser(ima, iuser); } *r_entry = frame; @@ -4955,7 +5016,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, } else if (ima->source == IMA_SRC_TILED) { if (ELEM(ima->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER)) { - entry = (iuser && iuser->tile) ? iuser->tile : 1001; + entry = image_get_tile_number_from_iuser(ima, iuser); ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry); if ((ima->type == IMA_TYPE_IMAGE) && ibuf != NULL) { @@ -5507,7 +5568,7 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) index = iuser ? iuser->framenr : ima->lastframe; } else { - index = (iuser && iuser->tile) ? iuser->tile : 1001; + index = image_get_tile_number_from_iuser(ima, iuser); } BLI_path_sequence_decode(filepath, head, tail, &numlen); diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c index bb7495437bb..d179dd40c33 100644 --- a/source/blender/blenkernel/intern/image_gpu.c +++ b/source/blender/blenkernel/intern/image_gpu.c @@ -108,8 +108,9 @@ static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multivi float array_w = GPU_texture_width(tilearray); float array_h = GPU_texture_height(tilearray); + /* Determine maximum tile number. */ + BKE_image_sort_tiles(ima); ImageTile *last_tile = (ImageTile *)ima->tiles.last; - /* Tiles are sorted by number. */ int max_tile = last_tile->tile_number - 1001; /* create image */ diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index 360bad3e786..be86da05b57 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -404,11 +404,12 @@ bool BKE_image_save( if (ima->source == IMA_SRC_TILED) { /* Verify filepath for tiles images. */ - if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) { + ImageTile *first_tile = ima->tiles.first; + if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) { BKE_reportf(reports, RPT_ERROR, - "When saving a tiled image, the path '%s' must contain the UDIM tag 1001", - opts->filepath); + "When saving a tiled image, the path '%s' must contain the UDIM tile number %d", + opts->filepath, first_tile->tile_number); return false; } @@ -430,9 +431,14 @@ bool BKE_image_save( BLI_path_sequence_decode(filepath, head, tail, &numlen); /* Save all other tiles. */ - LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { - /* Tile 1001 was already saved before the loop. */ - if (tile->tile_number == 1001 || !ok) { + int index; + LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) { + /* First tile was already saved before the loop. */ + if (index == 0) { + continue; + } + + if (!ok) { continue; } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 999d2956fef..29c1452b988 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1289,8 +1289,10 @@ static Image *image_open_single(Main *bmain, } if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) { - if (range->udim_tiles.first && range->offset == 1001) { + if (range->udim_tiles.first) { ima->source = IMA_SRC_TILED; + ImageTile *first_tile = ima->tiles.first; + first_tile->tile_number = range->offset; LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) { BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL); } @@ -1806,10 +1808,13 @@ static int image_save_options_init(Main *bmain, } /* append UDIM numbering if not present */ - if (ima->source == IMA_SRC_TILED && - (BLI_path_sequence_decode(ima->filepath, NULL, NULL, NULL) != 1001)) { + if (ima->source == IMA_SRC_TILED) { + char udim[6]; + ImageTile *tile = ima->tiles.first; + BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number); + int len = strlen(opts->filepath); - STR_CONCAT(opts->filepath, len, ".1001"); + STR_CONCAT(opts->filepath, len, udim); } } @@ -3868,9 +3873,9 @@ static void tile_fill_init(PointerRNA *ptr, Image *ima, ImageTile *tile) /* Acquire ibuf to get the default values. * If the specified tile has no ibuf, try acquiring the main tile instead - * (unless the specified tile already was the main tile). */ + * (unless the specified tile already was the first tile). */ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL && (tile != NULL) && (tile->tile_number != 1001)) { + if (ibuf == NULL && (tile != NULL) && (tile != ima->tiles.first)) { ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); } @@ -3932,27 +3937,30 @@ static int tile_add_exec(bContext *C, wmOperator *op) bool fill_tile = RNA_boolean_get(op->ptr, "fill"); char *label = RNA_string_get_alloc(op->ptr, "label", NULL, 0); - bool created_tile = false; + /* BKE_image_add_tile assumes a pre-sorted list of tiles. */ + BKE_image_sort_tiles(ima); + + ImageTile *last_tile_created = NULL; for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) { ImageTile *tile = BKE_image_add_tile(ima, tile_number, label); if (tile != NULL) { - ima->active_tile_index = BLI_findindex(&ima->tiles, tile); - if (fill_tile) { do_fill_tile(op->ptr, ima, tile); } - created_tile = true; + last_tile_created = tile; } } MEM_freeN(label); - if (!created_tile) { + if (!last_tile_created) { BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created"); return OPERATOR_CANCELLED; } + ima->active_tile_index = BLI_findindex(&ima->tiles, last_tile_created); + WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); return OPERATOR_FINISHED; } @@ -4041,7 +4049,7 @@ static bool tile_remove_poll(bContext *C) { Image *ima = CTX_data_edit_image(C); - return (ima != NULL && ima->source == IMA_SRC_TILED && ima->active_tile_index != 0); + return (ima != NULL && ima->source == IMA_SRC_TILED && !BLI_listbase_is_single(&ima->tiles)); } static int tile_remove_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 02546e3e3b3..288b3d94b1d 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -124,7 +124,7 @@ static int image_cmp_frame(const void *a, const void *b) * * udim_tiles may get filled even if the result ultimately is false! */ -static int image_get_udim(char *filepath, ListBase *udim_tiles) +static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range) { char filename[FILE_MAX], dirname[FILE_MAXDIR]; BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); @@ -133,12 +133,12 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) char base_head[FILE_MAX], base_tail[FILE_MAX]; int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits); - if (id < 1001 || id >= IMA_UDIM_MAX) { - return 0; + if (id < 1001 || id > IMA_UDIM_MAX) { + return false; } bool is_udim = true; - bool has_primary = false; + int min_udim = IMA_UDIM_MAX + 1; int max_udim = 0; struct direntry *dir; @@ -155,26 +155,27 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) continue; } - if (id < 1001 || id >= IMA_UDIM_MAX) { + if (id < 1001 || id > IMA_UDIM_MAX) { is_udim = false; break; } - if (id == 1001) { - has_primary = true; - } BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id))); + min_udim = min_ii(min_udim, id); max_udim = max_ii(max_udim, id); } BLI_filelist_free(dir, totfile); - if (is_udim && has_primary) { + if (is_udim && min_udim <= IMA_UDIM_MAX) { char primary_filename[FILE_MAX]; - BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, 1001); + BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim); BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename); - return max_udim - 1000; + + *udim_start = min_udim; + *udim_range = max_udim - min_udim + 1; + return true; } - return 0; + return false; } /** @@ -185,11 +186,12 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u { /* UDIM */ if (detect_udim) { - int len_udim = image_get_udim(range->filepath, &range->udim_tiles); + int udim_start, udim_range; + bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range); - if (len_udim > 0) { - range->offset = 1001; - range->length = len_udim; + if (result) { + range->offset = udim_start; + range->length = udim_range; return; } } diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index c058ab6cfcc..e44ddb07d53 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -290,15 +290,10 @@ static void rna_UDIMTile_tile_number_set(PointerRNA *ptr, int value) ImageTile *tile = (ImageTile *)ptr->data; Image *image = (Image *)ptr->owner_id; - /* The index of the first tile can't be changed. */ - if (tile->tile_number == 1001) { - return; - } - /* Check that no other tile already has that number. */ ImageTile *cur_tile = BKE_image_get_tile(image, value); - if (cur_tile == NULL || cur_tile == tile) { - tile->tile_number = value; + if (cur_tile == NULL) { + BKE_image_reassign_tile(image, tile, value); } } -- cgit v1.2.3 From c0f600cad1d2d107d189b15b12e2fcc6bba0985c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 18 Aug 2021 07:31:43 +0200 Subject: T73434: Improve Weight Paint Overlay Drawing. Master multiplied the weight paint on top of the rendered image. This reduced readability. This patch removes the multiplication for weight painting and adds a hint of the geometry below the overlay. Reviewed By: Mets, pablodp606, campbellbarton Maniphest Tasks: T73434 Differential Revision: https://developer.blender.org/D12170 --- .../blender/draw/engines/overlay/overlay_paint.c | 27 +++++++++++----------- .../blender/draw/engines/overlay/overlay_private.h | 2 +- .../blender/draw/engines/overlay/overlay_shader.c | 13 ++++++----- .../engines/overlay/shaders/paint_weight_frag.glsl | 23 ++++++++++-------- .../engines/overlay/shaders/paint_weight_vert.glsl | 15 ++++++++++++ source/blender/draw/tests/shaders_test.cc | 3 ++- 6 files changed, 52 insertions(+), 31 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c index d52640ed174..60a90616d29 100644 --- a/source/blender/draw/engines/overlay/overlay_paint.c +++ b/source/blender/draw/engines/overlay/overlay_paint.c @@ -92,18 +92,26 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata) case CTX_MODE_PAINT_WEIGHT: { opacity = is_edit_mode ? 1.0 : pd->overlay.weight_paint_mode_opacity; if (opacity > 0.0f) { - state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; - state |= pd->painting.alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state); - sh = OVERLAY_shader_paint_weight(); + const bool do_shading = draw_ctx->v3d->shading.type != OB_WIRE; + + sh = OVERLAY_shader_paint_weight(do_shading); pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "drawContours", draw_contours); - DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", pd->painting.alpha_blending); DRW_shgroup_uniform_float_copy(grp, "opacity", opacity); DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp); + /* Arbitrary light to give a hint of the geometry behind the weights. */ + if (do_shading) { + float light_dir[3]; + copy_v3_fl3(light_dir, 0.0f, 0.5f, 0.86602f); + normalize_v3(light_dir); + DRW_shgroup_uniform_vec3_copy(grp, "light_dir", light_dir); + } + if (pd->painting.alpha_blending) { state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRW_PASS_CREATE(psl->paint_depth_ps, state | pd->clipping_state); @@ -257,17 +265,10 @@ void OVERLAY_paint_draw(OVERLAY_Data *vedata) OVERLAY_PassList *psl = vedata->psl; OVERLAY_FramebufferList *fbl = vedata->fbl; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (DRW_state_is_fbo()) { - if (pd->painting.alpha_blending) { - GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb : - fbl->overlay_default_fb); - } - else { - /* Paint overlay needs final color because of multiply blend mode. */ - GPU_framebuffer_bind(pd->painting.in_front ? dfbl->in_front_fb : dfbl->default_fb); - } + GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb : + fbl->overlay_default_fb); } if (psl->paint_depth_ps) { diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 03bfaf56f24..68f60bee779 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -736,7 +736,7 @@ GPUShader *OVERLAY_shader_paint_face(void); GPUShader *OVERLAY_shader_paint_point(void); GPUShader *OVERLAY_shader_paint_texture(void); GPUShader *OVERLAY_shader_paint_vertcol(void); -GPUShader *OVERLAY_shader_paint_weight(void); +GPUShader *OVERLAY_shader_paint_weight(bool shading); GPUShader *OVERLAY_shader_paint_wire(void); GPUShader *OVERLAY_shader_particle_dot(void); GPUShader *OVERLAY_shader_particle_shape(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 7a7ae9a921b..edf9148c8c0 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -211,7 +211,7 @@ typedef struct OVERLAY_Shaders { GPUShader *paint_point; GPUShader *paint_texture; GPUShader *paint_vertcol; - GPUShader *paint_weight; + GPUShader *paint_weight[2]; GPUShader *paint_wire; GPUShader *particle_dot; GPUShader *particle_shape; @@ -1334,13 +1334,14 @@ GPUShader *OVERLAY_shader_paint_vertcol(void) return sh_data->paint_vertcol; } -GPUShader *OVERLAY_shader_paint_weight(void) +GPUShader *OVERLAY_shader_paint_weight(const bool shading) { + int index = shading ? 1 : 0; const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->paint_weight) { - sh_data->paint_weight = GPU_shader_create_from_arrays({ + if (!sh_data->paint_weight[index]) { + sh_data->paint_weight[index] = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -1349,10 +1350,10 @@ GPUShader *OVERLAY_shader_paint_weight(void) .frag = (const char *[]){datatoc_common_globals_lib_glsl, datatoc_paint_weight_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .defs = (const char *[]){sh_cfg->def, shading ? "#define FAKE_SHADING\n" : "", NULL}, }); } - return sh_data->paint_weight; + return sh_data->paint_weight[index]; } GPUShader *OVERLAY_shader_paint_wire(void) diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl index 0020d76ed6a..8009713d655 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl @@ -1,12 +1,12 @@ in vec2 weight_interp; /* (weight, alert) */ +in float color_fac; out vec4 fragColor; uniform float opacity = 1.0; uniform sampler1D colorramp; -uniform bool useAlphaBlend = false; uniform bool drawContours = false; float contours(float value, float steps, float width_px, float max_rel_width, float gradient) @@ -68,6 +68,13 @@ vec4 contour_grid(float weight, float weight_gradient) return grid * clamp((weight_gradient - flt_eps) / flt_eps, 0.0, 1.0); } +vec4 apply_color_fac(vec4 color_in) +{ + vec4 color = color_in; + color.rgb = max(vec3(0.005), color_in.rgb) * color_fac; + return color; +} + void main() { float alert = weight_interp.y; @@ -75,12 +82,13 @@ void main() /* Missing vertex group alert color. Uniform in practice. */ if (alert > 1.1) { - color = colorVertexMissingData; + color = apply_color_fac(colorVertexMissingData); } /* Weights are available */ else { float weight = weight_interp.x; vec4 weight_color = texture(colorramp, weight, 0); + weight_color = apply_color_fac(weight_color); /* Contour display */ if (drawContours) { @@ -93,14 +101,9 @@ void main() } /* Zero weight alert color. Nonlinear blend to reduce impact. */ - color = mix(weight_color, colorVertexUnreferenced, alert * alert); + vec4 color_unreferenced = apply_color_fac(colorVertexUnreferenced); + color = mix(weight_color, color_unreferenced, alert * alert); } - if (useAlphaBlend) { - fragColor = vec4(color.rgb, opacity); - } - else { - /* mix with 1.0 -> is like opacity when using multiply blend mode */ - fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0); - } + fragColor = vec4(color.rgb, opacity); } diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl index b3baa8c7b07..31b6dc42cf4 100644 --- a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl @@ -1,8 +1,13 @@ +#ifdef FAKE_SHADING +uniform vec3 light_dir; +#endif in float weight; in vec3 pos; +in vec3 nor; out vec2 weight_interp; /* (weight, alert) */ +out float color_fac; void main() { @@ -14,6 +19,16 @@ void main() /* Separate actual weight and alerts for independent interpolation */ weight_interp = max(vec2(weight, -weight), 0.0); + /* Saturate the weight to give a hint of the geometry behind the weights. */ +#ifdef FAKE_SHADING + vec3 view_normal = normalize(normal_object_to_view(nor)); + color_fac = abs(dot(view_normal, light_dir)); + color_fac = color_fac * 0.9 + 0.1; + +#else + color_fac = 1.0; +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index 0c7cbd4dac8..a9810b4cc77 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -267,7 +267,8 @@ static void test_overlay_glsl_shaders() EXPECT_NE(OVERLAY_shader_paint_point(), nullptr); EXPECT_NE(OVERLAY_shader_paint_texture(), nullptr); EXPECT_NE(OVERLAY_shader_paint_vertcol(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_weight(), nullptr); + EXPECT_NE(OVERLAY_shader_paint_weight(false), nullptr); + EXPECT_NE(OVERLAY_shader_paint_weight(true), nullptr); EXPECT_NE(OVERLAY_shader_paint_wire(), nullptr); EXPECT_NE(OVERLAY_shader_particle_dot(), nullptr); EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr); -- cgit v1.2.3 From 7bffafab7b2a489c9f0eafd576f9da0cbc1a5081 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 17 Aug 2021 18:25:53 -0300 Subject: Fix T90718: Object selection toggle do not work inside edit mode The object was not deselected as it was expected that it would be activated. But this activation does not happen in edit mode. --- source/blender/editors/space_view3d/view3d_select.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2ce5684e874..e3f97dd1c63 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2521,6 +2521,7 @@ static bool ed_object_select_pick(bContext *C, } /* also prevent making it active on mouse selection */ else if (BASE_SELECTABLE(v3d, basact)) { + const bool use_activate_selected_base = (oldbasact != basact) && (is_obedit == false); if (extend) { ED_object_base_select(basact, BA_SELECT); } @@ -2529,7 +2530,8 @@ static bool ed_object_select_pick(bContext *C, } else if (toggle) { if (basact->flag & BASE_SELECTED) { - if (basact == oldbasact) { + /* Keep selected if the base is to be activated. */ + if (use_activate_selected_base == false) { ED_object_base_select(basact, BA_DESELECT); } } @@ -2545,7 +2547,7 @@ static bool ed_object_select_pick(bContext *C, } } - if ((oldbasact != basact) && (is_obedit == false)) { + if (use_activate_selected_base) { ED_object_base_activate(C, basact); /* adds notifier */ if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) { WM_toolsystem_update_from_context_view3d(C); -- cgit v1.2.3 From 787350dde8aec3caf8660c749e1847ff406974c8 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 18 Aug 2021 12:45:37 +0200 Subject: Fix T90737: VSE adding nested strips could have non-unique names Caused by {rBbbb1936411a5}. When adding strips via the new SEQ_add_XXX_strip functions, the `Editing->seqbasep` pointer was passed around. Following in `seq_add_generic_update` this `seqbasep` pointer was used to ensure a unique name. But `seqbasep` is the pointer to the current list of seq's being edited (**which can be limited to the ones within a meta strip**). We need unique names across all strips though (since these are used for RNA paths, FCurves as reported), so now use the scene's `Editing- >seqbase` (**which is the list of the top-most sequences**) instead. Unfortunately this might have screwed files to a borked state, not sure if this could easily be fixed... Maniphest Tasks: T90737 Differential Revision: https://developer.blender.org/D12256 --- source/blender/sequencer/intern/strip_add.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 7b383bcb330..9081c655d2f 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -99,7 +99,7 @@ void SEQ_add_load_data_init(SeqLoadData *load_data, static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq) { - SEQ_sequence_base_unique_name_recursive(scene, seqbase, seq); + SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq); SEQ_time_update_sequence_bounds(scene, seq); SEQ_sort(seqbase); SEQ_relations_invalidate_cache_composite(scene, seq); -- cgit v1.2.3 From 04376c3bac796c9fb4bc2e33150484e357a65eab Mon Sep 17 00:00:00 2001 From: Charlie Jolly Date: Wed, 18 Aug 2021 13:16:14 +0100 Subject: Geometry Nodes: Add shader Color Mix node Port color mix shader node to Geometry Nodes. Differential Revision: https://developer.blender.org/D10585 --- .../nodes/shader/nodes/node_shader_mixRgb.cc | 58 +++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc index 6baaa17f956..47011caeeb6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc @@ -127,15 +127,71 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat, return 0; } +class MixRGBFunction : public blender::fn::MultiFunction { + private: + bool clamp_; + int type_; + + public: + MixRGBFunction(bool clamp, int type) : clamp_(clamp), type_(type) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"MixRGB"}; + signature.single_input("Fac"); + signature.single_input("Color1"); + signature.single_input("Color2"); + signature.single_output("Color"); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray &fac = params.readonly_single_input(0, "Fac"); + const blender::VArray &col1 = + params.readonly_single_input(1, "Color1"); + const blender::VArray &col2 = + params.readonly_single_input(2, "Color2"); + blender::MutableSpan results = + params.uninitialized_single_output(3, "Color"); + + for (int64_t i : mask) { + results[i] = col1[i]; + ramp_blend(type_, results[i], clamp_f(fac[i], 0.0f, 1.0f), col2[i]); + } + + if (clamp_) { + for (int64_t i : mask) { + clamp_v3(results[i], 0.0f, 1.0f); + } + } + } +}; + +static void sh_node_mix_rgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +{ + bNode &node = builder.bnode(); + bool clamp = node.custom2 & SHD_MIXRGB_CLAMP; + int mix_type = node.custom1; + builder.construct_and_set_matching_fn(clamp, mix_type); +} + void register_node_type_sh_mix_rgb(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out); node_type_label(&ntype, node_blend_label); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb); node_type_gpu(&ntype, gpu_shader_mix_rgb); + ntype.expand_in_mf_network = sh_node_mix_rgb_expand_in_mf_network; nodeRegisterType(&ntype); } -- cgit v1.2.3 From 9bfd4ae22293caedfb8e150512cc911bfc95d35f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Aug 2021 12:53:15 +0200 Subject: LibOverride: tweak resync detection code at apply phase. This code checks whether an ID pointer property of an override does not match its linked reference when it is expected to do so. This is a goiod indication that a resync is needed. Previous code would falsy detect overrides of IDs referencing themselves as needing a resync, when this is not effectively the case. --- .../makesrna/intern/rna_access_compare_override.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 3912c873fd0..2c552970c82 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -1096,6 +1096,7 @@ static void rna_property_override_check_resync(Main *bmain, PointerRNA *ptr_item_dst, PointerRNA *ptr_item_src) { + ID *id_owner = rna_property_override_property_real_id_owner(bmain, ptr_dst, NULL, NULL); ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, NULL, NULL); ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL); @@ -1109,9 +1110,18 @@ static void rna_property_override_check_resync(Main *bmain, * remapped to its new local override. In that case overrides and linked data * are always properly matching. */ id_src != id_dst && - /* If one of the pointers is NULL and not the other, or if linked reference ID - * of `id_src` is not `id_dst`, we are in a non-matching case. */ - (ELEM(NULL, id_src, id_dst) || id_src->override_library->reference != id_dst)) { + /* If one of the pointers is NULL and not the other, we are in a non-matching case. */ + (ELEM(NULL, id_src, id_dst) || + /* If `id_dst` is not from same lib as id_src, and linked reference ID of `id_src` is not + * `id_dst`, we are in a non-matching case. */ + (id_dst->lib != id_src->lib && id_src->override_library->reference != id_dst) || + /* If `id_dst` is from same lib as id_src, and is not same as `id_owner`, we are in a + * non-matching case. + * + * NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new + * override copy generated by `BKE_lib_override_library_update` will already have its + * self-references updated to itself, instead of still pointing to its linked source. */ + (id_dst->lib == id_src->lib && id_dst != id_owner))) { ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name); } -- cgit v1.2.3 From ba71eb467e46b33b0066ee6a05062f686d9af354 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Aug 2021 12:56:31 +0200 Subject: LibOverride: Add several missing 'OVERRIDABLE' flags to NodeTrees RNA. This should be a no-change commit for now, but is required to enable initial basic support of nodetrees in library override. NOTE: Proper full support of liboverrides in nodes is yet to be designed (has UX unresolved issues, since we likely do not want to expose/make overridable ALL settings of ALL nodes). --- source/blender/makesrna/intern/rna_nodetree.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 7d5fffcc6c9..d8ab7c7a61b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4745,6 +4745,7 @@ static void def_frame(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Text", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -5752,6 +5753,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna) NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE); @@ -6171,6 +6173,7 @@ static void def_sh_tex_ies(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "IES Text", "Internal IES file"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -6211,6 +6214,7 @@ static void def_sh_script(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Script", "Internal shader script to define the shader"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScript_update"); @@ -7936,6 +7940,7 @@ static void def_cmp_movieclip(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -7950,6 +7955,7 @@ static void def_cmp_stabilize2d(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -7980,6 +7986,7 @@ static void def_cmp_moviedistortion(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8009,6 +8016,7 @@ static void def_cmp_mask(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Mask"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Mask", ""); prop = RNA_def_property(srna, "use_feather", PROP_BOOLEAN, PROP_NONE); @@ -8501,6 +8509,7 @@ static void def_cmp_keyingscreen(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8638,6 +8647,7 @@ static void def_cmp_trackpos(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8702,6 +8712,7 @@ static void def_cmp_planetrackdeform(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8832,6 +8843,7 @@ static void def_cmp_cryptomatte(StructRNA *srna) prop, "rna_NodeCryptomatte_scene_get", "rna_NodeCryptomatte_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Scene", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8843,6 +8855,7 @@ static void def_cmp_cryptomatte(StructRNA *srna) "rna_NodeCryptomatte_image_poll"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -8942,6 +8955,7 @@ static void def_tex_image(StructRNA *srna) RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -10929,6 +10943,7 @@ static void rna_def_node_socket_object(BlenderRNA *brna, RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); @@ -10964,6 +10979,7 @@ static void rna_def_node_socket_image(BlenderRNA *brna, RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); @@ -11014,6 +11030,7 @@ static void rna_def_node_socket_collection(BlenderRNA *brna, RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); @@ -11049,6 +11066,7 @@ static void rna_def_node_socket_texture(BlenderRNA *brna, RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); @@ -11086,6 +11104,7 @@ static void rna_def_node_socket_material(BlenderRNA *brna, RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); @@ -11471,12 +11490,14 @@ static void rna_def_node(BlenderRNA *brna) prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Inputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_IN); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Outputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_OUT); @@ -11923,6 +11944,7 @@ static void rna_def_nodetree(BlenderRNA *brna) prop = RNA_def_property(srna, "nodes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "nodes", NULL); RNA_def_property_struct_type(prop, "Node"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Nodes", ""); rna_def_nodetree_nodes_api(brna, prop); @@ -11940,6 +11962,7 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_property_pointer_funcs( prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block"); RNA_def_property_update(prop, NC_NODE, NULL); -- cgit v1.2.3 From 1d06d35034e6b9485c61c1f6fea28603ba123ee6 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Aug 2021 16:44:14 +0200 Subject: LibOverride: Do not report embedded IDs as non-overridable in 'foreach_id' code. Embedded IDs (root nodetrees, master collection, etc.) pointer itself is not editable, but their content may be overridden. LibOverride code is supposed to know how to handle those embedded IDs. --- source/blender/blenkernel/intern/lib_query.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 977e53c8474..9400458376d 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -88,8 +88,8 @@ bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int /* Update the callback flags with some extra information regarding overrides: all 'loopback', * 'internal', 'embedded' etc. ID pointers are never overridable. */ - if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_EMBEDDED | IDWALK_CB_LOOPBACK | - IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + if (cb_flag & + (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; } -- cgit v1.2.3 From fffe219bdb8d12e1c6a06bb38e68150ab9e40038 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Aug 2021 16:46:12 +0200 Subject: LibOverride: Make nodetree of material overrideable again. This reverts rB6899dbef77cd and makes the pointer explicitely processable by override & diffing code. Previous changes & fixes have fixed the 'driver-workaround' case afaict. Note that this only enables proper generic handling of overrides and their ID pointers, no node property is actually overridable currently. --- source/blender/makesrna/intern/rna_material.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index d91c0bfaf29..ee31b92b2a1 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -850,7 +850,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); /* XXX: remove once overrides in material node trees are supported. */ - RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based materials"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); -- cgit v1.2.3 From e5f8db92b696a36e919eb6ac3125190d9e2202d9 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Aug 2021 17:05:49 +0200 Subject: LibOverride: Tag all embedded IDs RNA opinters as overridable. Followup to previous commit, rBfffe219bdb8drBfffe219bdb8d Again this is only for sake of sane ID/overrides managment for now, the nodetrees themselves are not overridable from user PoV yet. --- source/blender/makesrna/intern/rna_material.c | 1 - source/blender/makesrna/intern/rna_scene.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index ee31b92b2a1..144950235c8 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -849,7 +849,6 @@ void RNA_def_material(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); - /* XXX: remove once overrides in material node trees are supported. */ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based materials"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 7d7eec6f256..f0a1508fb5f 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -7664,6 +7664,7 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Compositing node tree"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); @@ -7895,6 +7896,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "master_collection"); RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Collection", "Scene root collection that owns all the objects and other collections " -- cgit v1.2.3 From ac09411368a968fd1d90aef2362654d5007b6b48 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 12:15:04 +1000 Subject: Cleanup: unused warning --- source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index e8dd36e528c..49664323e89 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -37,7 +37,7 @@ static bNodeSocketTemplate geo_node_subdivision_surface_out[] = { static void geo_node_subdivision_surface_layout(uiLayout *layout, bContext *UNUSED(C), - PointerRNA *ptr) + PointerRNA *UNUSED(ptr)) { #ifndef WITH_OPENSUBDIV uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); -- cgit v1.2.3 From feaa61a9680844d0fdc5b9b1a1407819fbb6dc97 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 18 Aug 2021 19:48:30 -0700 Subject: UI: Remove "Unfitted" Kerning Style Option This patch removes the "Kerning Style" option for UI widget font drawing and uses only the current default of "Fitted", since the other option of "Unfitted" is just the result of truncation errors. see D12231 for much more information. Differential Revision: https://developer.blender.org/D12231 Reviewed by Campbell Barton --- source/blender/blenfont/BLF_api.h | 2 +- source/blender/blenfont/intern/blf_font.c | 4 +- .../blender/editors/interface/interface_handlers.c | 9 ---- source/blender/editors/interface/interface_panel.c | 8 ---- .../editors/interface/interface_region_tooltip.c | 3 -- source/blender/editors/interface/interface_style.c | 45 +----------------- .../blender/editors/interface/interface_widgets.c | 53 ---------------------- source/blender/editors/space_file/filesel.c | 14 +----- source/blender/makesdna/DNA_userdef_types.h | 3 +- source/blender/makesrna/intern/rna_userdef.c | 12 ----- source/blender/python/generic/blf_py_api.c | 1 - 11 files changed, 5 insertions(+), 149 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 7e92f79a523..eb3f9805240 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -271,7 +271,7 @@ void BLF_state_print(int fontid); #define BLF_ROTATION (1 << 0) #define BLF_CLIPPING (1 << 1) #define BLF_SHADOW (1 << 2) -#define BLF_KERNING_DEFAULT (1 << 3) +// #define BLF_FLAG_UNUSED_3 (1 << 3) /* dirty */ #define BLF_MATRIX (1 << 4) #define BLF_ASPECT (1 << 5) #define BLF_WORD_WRAP (1 << 6) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index d9396bd0f90..36eca3c00e6 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -355,9 +355,7 @@ BLI_INLINE GlyphBLF *blf_utf8_next_fast( #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \ const bool _has_kerning = FT_HAS_KERNING((_font)->face); \ - const FT_UInt _kern_mode = (_has_kerning && !((_font)->flags & BLF_KERNING_DEFAULT)) ? \ - FT_KERNING_UNFITTED : \ - FT_KERNING_DEFAULT; + const FT_UInt _kern_mode = FT_KERNING_DEFAULT; BLI_INLINE void blf_kerning_step_fast(FontBLF *font, const FT_UInt kern_mode, diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6f2232fabe5..b8f324cba83 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3086,11 +3086,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con UI_fontstyle_set(&fstyle); - if (fstyle.kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle.uifont_id, BLF_KERNING_DEFAULT); - } - ui_but_text_password_hide(password_str, but, false); if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { @@ -3141,10 +3136,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con but->pos = glyph_data[1] + but->ofs; } - if (fstyle.kerning == 1) { - BLF_disable(fstyle.uifont_id, BLF_KERNING_DEFAULT); - } - ui_but_text_password_hide(password_str, but, true); } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 97d01ac3763..a64797af24f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1447,10 +1447,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) is_alpha = (region->overlap && (theme_col_back[3] != 255)); - if (fstyle->kerning == 1) { - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - BLF_enable(fontid, BLF_ROTATION); BLF_rotation(fontid, M_PI_2); // UI_fontstyle_set(&style->widget); @@ -1620,10 +1616,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) GPU_line_smooth(false); BLF_disable(fontid, BLF_ROTATION); - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } } #undef TABS_PADDING_BETWEEN_FACTOR diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 10bc3760b42..a8f289702f8 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -1175,9 +1175,6 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, winx - (UI_TIP_PADDING * 2)); font_flag |= BLF_WORD_WRAP; - if (data->fstyle.kerning == 1) { - font_flag |= BLF_KERNING_DEFAULT; - } BLF_enable(data->fstyle.uifont_id, font_flag); BLF_enable(blf_mono_font, font_flag); BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 88ab6a377d0..804156ba48c 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -83,7 +83,6 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id style->paneltitle.uifont_id = uifont_id; style->paneltitle.points = UI_DEFAULT_TITLE_POINTS; - style->paneltitle.kerning = 1; style->paneltitle.shadow = 3; style->paneltitle.shadx = 0; style->paneltitle.shady = -1; @@ -92,7 +91,6 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id style->grouplabel.uifont_id = uifont_id; style->grouplabel.points = UI_DEFAULT_TITLE_POINTS; - style->grouplabel.kerning = 1; style->grouplabel.shadow = 3; style->grouplabel.shadx = 0; style->grouplabel.shady = -1; @@ -101,7 +99,6 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id style->widgetlabel.uifont_id = uifont_id; style->widgetlabel.points = UI_DEFAULT_TEXT_POINTS; - style->widgetlabel.kerning = 1; style->widgetlabel.shadow = 3; style->widgetlabel.shadx = 0; style->widgetlabel.shady = -1; @@ -110,7 +107,6 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id style->widget.uifont_id = uifont_id; style->widget.points = UI_DEFAULT_TEXT_POINTS; - style->widget.kerning = 1; style->widget.shadow = 1; style->widget.shady = -1; style->widget.shadowalpha = 0.5f; @@ -164,9 +160,6 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, BLF_shadow(fs->uifont_id, fs->shadow, shadow_color); BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); } - if (fs->kerning == 1) { - font_flag |= BLF_KERNING_DEFAULT; - } if (fs_params->word_wrap == 1) { font_flag |= BLF_WORD_WRAP; } @@ -278,19 +271,12 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, BLF_shadow_offset(fs->uifont_id, fs->shadx, fs->shady); } - if (fs->kerning == 1) { - BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - } - BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); BLF_disable(fs->uifont_id, BLF_ROTATION); BLF_disable(fs->uifont_id, BLF_CLIPPING); if (fs->shadow) { BLF_disable(fs->uifont_id, BLF_SHADOW); } - if (fs->kerning == 1) { - BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); - } } /** @@ -302,18 +288,10 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, void UI_fontstyle_draw_simple( const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4]) { - if (fs->kerning == 1) { - BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - } - UI_fontstyle_set(fs); BLF_position(fs->uifont_id, x, y, 0.0f); BLF_color4ubv(fs->uifont_id, col); BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - - if (fs->kerning == 1) { - BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); - } } /** @@ -326,10 +304,6 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs, const float col_fg[4], const float col_bg[4]) { - if (fs->kerning == 1) { - BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - } - UI_fontstyle_set(fs); { @@ -357,10 +331,6 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs, BLF_position(fs->uifont_id, x, y, 0.0f); BLF_color4fv(fs->uifont_id, col_fg); BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - - if (fs->kerning == 1) { - BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); - } } /* ************** helpers ************************ */ @@ -405,21 +375,8 @@ const uiStyle *UI_style_get_dpi(void) int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) { - int width; - - if (fs->kerning == 1) { - /* for BLF_width */ - BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - } - UI_fontstyle_set(fs); - width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - - if (fs->kerning == 1) { - BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); - } - - return width; + return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); } int UI_fontstyle_height_max(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index d3481c449ac..48f638dac33 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1576,11 +1576,6 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, /* need to set this first */ UI_fontstyle_set(fstyle); - if (fstyle->kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - float strwidth = BLF_width(fstyle->uifont_id, str, max_len); if ((okwidth > 0.0f) && (strwidth > okwidth)) { @@ -1674,10 +1669,6 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, strwidth = BLF_width(fstyle->uifont_id, str, max_len); } - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - BLI_assert(strwidth <= okwidth); return strwidth; @@ -1736,11 +1727,6 @@ static void ui_text_clip_cursor(const uiFontStyle *fstyle, uiBut *but, const rct /* need to set this first */ UI_fontstyle_set(fstyle); - if (fstyle->kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - /* define ofs dynamically */ if (but->ofs > but->pos) { but->ofs = but->pos; @@ -1785,10 +1771,6 @@ static void ui_text_clip_cursor(const uiFontStyle *fstyle, uiBut *but, const rct } } } - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } } /** @@ -1806,11 +1788,6 @@ static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, cons /* need to set this first */ UI_fontstyle_set(fstyle); - if (fstyle->kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr)); but->ofs = 0; @@ -1870,10 +1847,6 @@ static void ui_text_clip_right_label(const uiFontStyle *fstyle, uiBut *but, cons but->strwidth = strwidth; but->drawstr[drawstr_len] = 0; } - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } } #ifdef WITH_INPUT_IME @@ -1985,11 +1958,6 @@ static void widget_draw_text(const uiFontStyle *fstyle, align = UI_STYLE_TEXT_CENTER; } - if (fstyle->kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - /* Special case: when we're entering text for multiple buttons, * don't draw the text for any of the multi-editing buttons */ if (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI)) { @@ -2151,10 +2119,6 @@ static void widget_draw_text(const uiFontStyle *fstyle, #endif } - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - #if 0 ui_rasterpos_safe(x, y, but->aspect); transopts = ui_translate_buttons(); @@ -2232,10 +2196,6 @@ static void widget_draw_text(const uiFontStyle *fstyle, } if (ul_index != -1) { - if (fstyle->kerning == 1) { - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2)); struct UnderlineData ul_data = { @@ -2256,10 +2216,6 @@ static void widget_draw_text(const uiFontStyle *fstyle, BLF_position(fstyle->uifont_id, pos_x, pos_y, 0.0f); BLF_color4ubv(fstyle->uifont_id, wcol->text); BLF_draw(fstyle->uifont_id, "_", 2); - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } } } } @@ -5369,11 +5325,6 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, /* need to set this first */ UI_fontstyle_set(fstyle); - if (fstyle->kerning == 1) { - /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } - if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) { /* Shrink rect to exclude the shortcut string. */ rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; @@ -5398,10 +5349,6 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, else { BLI_assert_msg(0, "Unknwon menu item separator type"); } - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } } } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 72e7e0716db..4ab7014cf82 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -863,20 +863,8 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, float file_string_width(const char *str) { const uiStyle *style = UI_style_get(); - float width; - UI_fontstyle_set(&style->widget); - if (style->widget.kerning == 1) { /* for BLF_width */ - BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT); - } - - width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - - if (style->widget.kerning == 1) { - BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT); - } - - return width; + return BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); } float file_font_pointsize(void) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 28acf5413b8..27376432092 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -71,14 +71,13 @@ typedef struct uiFontStyle { short uifont_id; /** Actual size depends on 'global' dpi. */ short points; - /** Unfitted or default kerning value. */ - short kerning; /** Style hint. */ short italic, bold; /** Value is amount of pixels blur. */ short shadow; /** Shadow offset in pixels. */ short shadx, shady; + char _pad0[2]; /** Total alpha. */ float shadowalpha; /** 1 value, typically white or black anyway. */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 483506d5733..73811924c23 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1118,12 +1118,6 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem font_kerning_style[] = { - {0, "UNFITTED", 0, "Unfitted", "Use scaled but un-grid-fitted kerning distances"}, - {1, "FITTED", 0, "Fitted", "Use scaled and grid-fitted kerning distances"}, - {0, NULL, 0, NULL, NULL}, - }; - srna = RNA_def_struct(brna, "ThemeFontStyle", NULL); RNA_def_struct_sdna(srna, "uiFontStyle"); RNA_def_struct_clear_flag(srna, STRUCT_UNDO); @@ -1134,12 +1128,6 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Points", "Font size in points"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); - prop = RNA_def_property(srna, "font_kerning_style", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "kerning"); - RNA_def_property_enum_items(prop, font_kerning_style); - RNA_def_property_ui_text(prop, "Kerning Style", "Which style to use for font kerning"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); - prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL); RNA_def_property_range(prop, 0, 5); RNA_def_property_ui_text(prop, "Shadow Size", "Shadow size (0, 3 and 5 supported)"); diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 0ec66e22fa9..9e725730d40 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -493,7 +493,6 @@ PyObject *BPyInit_blf(void) PyModule_AddIntConstant(submodule, "ROTATION", BLF_ROTATION); PyModule_AddIntConstant(submodule, "CLIPPING", BLF_CLIPPING); PyModule_AddIntConstant(submodule, "SHADOW", BLF_SHADOW); - PyModule_AddIntConstant(submodule, "KERNING_DEFAULT", BLF_KERNING_DEFAULT); PyModule_AddIntConstant(submodule, "WORD_WRAP", BLF_WORD_WRAP); PyModule_AddIntConstant(submodule, "MONOCHROME", BLF_MONOCHROME); -- cgit v1.2.3 From 7a4ef5256a383c2aba4585a2b80ff715b52bf73b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 12:36:23 +1000 Subject: Cleanup: reduce indentation in loops that check region visibility --- source/blender/windowmanager/intern/wm_draw.c | 156 +++++++++++---------- source/blender/windowmanager/intern/wm_operators.c | 7 +- 2 files changed, 88 insertions(+), 75 deletions(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index dcb918747f3..328950cf8f9 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -691,46 +691,48 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) /* Then do actual drawing of regions. */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->visible && region->do_draw) { - CTX_wm_region_set(C, region); - bool use_viewport = WM_region_use_viewport(area, region); - - GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion"); - - if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) { - wm_draw_region_buffer_create(region, true, use_viewport); - - for (int view = 0; view < 2; view++) { - eStereoViews sview; - if (view == 0) { - sview = STEREO_LEFT_ID; - } - else { - sview = STEREO_RIGHT_ID; - wm_draw_region_stereo_set(bmain, area, region, sview); - } - - wm_draw_region_bind(region, view); - ED_region_do_draw(C, region); - wm_draw_region_unbind(region); + if (!region->visible || !region->do_draw) { + continue; + } + + CTX_wm_region_set(C, region); + bool use_viewport = WM_region_use_viewport(area, region); + + GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion"); + + if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) { + wm_draw_region_buffer_create(region, true, use_viewport); + + for (int view = 0; view < 2; view++) { + eStereoViews sview; + if (view == 0) { + sview = STEREO_LEFT_ID; } - if (use_viewport) { - GPUViewport *viewport = region->draw_buffer->viewport; - GPU_viewport_stereo_composite(viewport, win->stereo3d_format); + else { + sview = STEREO_RIGHT_ID; + wm_draw_region_stereo_set(bmain, area, region, sview); } - } - else { - wm_draw_region_buffer_create(region, false, use_viewport); - wm_draw_region_bind(region, 0); + + wm_draw_region_bind(region, view); ED_region_do_draw(C, region); wm_draw_region_unbind(region); } + if (use_viewport) { + GPUViewport *viewport = region->draw_buffer->viewport; + GPU_viewport_stereo_composite(viewport, win->stereo3d_format); + } + } + else { + wm_draw_region_buffer_create(region, false, use_viewport); + wm_draw_region_bind(region, 0); + ED_region_do_draw(C, region); + wm_draw_region_unbind(region); + } - GPU_debug_group_end(); + GPU_debug_group_end(); - region->do_draw = false; - CTX_wm_region_set(C, NULL); - } + region->do_draw = false; + CTX_wm_region_set(C, NULL); } CTX_wm_area_set(C, NULL); @@ -740,29 +742,30 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) /* Draw menus into their own framebuffer. */ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { - if (region->visible) { - CTX_wm_menu_set(C, region); + if (!region->visible) { + continue; + } + CTX_wm_menu_set(C, region); - GPU_debug_group_begin("Menu"); + GPU_debug_group_begin("Menu"); - if (region->type && region->type->layout) { - /* UI code reads the OpenGL state, but we have to refresh - * the UI layout beforehand in case the menu size changes. */ - wmViewport(®ion->winrct); - region->type->layout(C, region); - } + if (region->type && region->type->layout) { + /* UI code reads the OpenGL state, but we have to refresh + * the UI layout beforehand in case the menu size changes. */ + wmViewport(®ion->winrct); + region->type->layout(C, region); + } - wm_draw_region_buffer_create(region, false, false); - wm_draw_region_bind(region, 0); - GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f); - ED_region_do_draw(C, region); - wm_draw_region_unbind(region); + wm_draw_region_buffer_create(region, false, false); + wm_draw_region_bind(region, 0); + GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f); + ED_region_do_draw(C, region); + wm_draw_region_unbind(region); - GPU_debug_group_end(); + GPU_debug_group_end(); - region->do_draw = false; - CTX_wm_menu_set(C, NULL); - } + region->do_draw = false; + CTX_wm_menu_set(C, NULL); } } @@ -786,8 +789,12 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Blit non-overlapping area regions. */ ED_screen_areas_iter (win, screen, area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->visible && region->overlap == false) { - /* Blit from offscreen buffer. */ + if (!region->visible) { + continue; + } + + if (region->overlap == false) { + /* Blit from off-screen buffer. */ wm_draw_region_blit(region, view); } } @@ -796,24 +803,25 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Draw overlays and paint cursors. */ ED_screen_areas_iter (win, screen, area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->visible) { - const bool do_paint_cursor = (wm->paintcursors.first && region == screen->active_region); - const bool do_draw_overlay = (region->type && region->type->draw_overlay); - if (!(do_paint_cursor || do_draw_overlay)) { - continue; - } + if (!region->visible) { + continue; + } + const bool do_paint_cursor = (wm->paintcursors.first && region == screen->active_region); + const bool do_draw_overlay = (region->type && region->type->draw_overlay); + if (!(do_paint_cursor || do_draw_overlay)) { + continue; + } - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); - if (do_draw_overlay) { - wm_region_draw_overlay(C, area, region); - } - if (do_paint_cursor) { - wm_paintcursor_draw(C, area, region); - } - CTX_wm_region_set(C, NULL); - CTX_wm_area_set(C, NULL); + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + if (do_draw_overlay) { + wm_region_draw_overlay(C, area, region); + } + if (do_paint_cursor) { + wm_paintcursor_draw(C, area, region); } + CTX_wm_region_set(C, NULL); + CTX_wm_area_set(C, NULL); } } wmWindowViewport(win); @@ -821,7 +829,10 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Blend in overlapping area regions */ ED_screen_areas_iter (win, screen, area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->visible && region->overlap) { + if (!region->visible) { + continue; + } + if (region->overlap) { wm_draw_region_blend(region, 0, true); } } @@ -834,9 +845,10 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Blend in floating regions (menus). */ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { - if (region->visible) { - wm_draw_region_blend(region, 0, true); + if (!region->visible) { + continue; } + wm_draw_region_blend(region, 0, true); } /* always draw, not only when screen tagged */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 50db8e73844..b5a038757c2 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -3178,10 +3178,11 @@ static void redraw_timer_step(bContext *C, LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) { CTX_wm_area_set(C, area_iter); LISTBASE_FOREACH (ARegion *, region_iter, &area_iter->regionbase) { - if (region_iter->visible) { - CTX_wm_region_set(C, region_iter); - wm_draw_region_test(C, area_iter, region_iter); + if (!region_iter->visible) { + continue; } + CTX_wm_region_set(C, region_iter); + wm_draw_region_test(C, area_iter, region_iter); } } -- cgit v1.2.3 From 594790d8a56777c4436b4da2165113d59d57283a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 12:49:10 +1000 Subject: UI: add function to access the buttons text without it's shortcut --- source/blender/editors/interface/interface_context_menu.c | 8 +------- source/blender/editors/interface/interface_intern.h | 2 ++ source/blender/editors/interface/interface_query.c | 7 +++++++ 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 8ace057891d..b953d88c896 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -373,13 +373,7 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um) BLI_assert(ui_but_is_user_menu_compatible(C, but)); char drawstr[sizeof(but->drawstr)]; - STRNCPY(drawstr, but->drawstr); - if (but->flag & UI_BUT_HAS_SEP_CHAR) { - char *sep = strrchr(drawstr, UI_SEP_CHAR); - if (sep) { - *sep = '\0'; - } - } + ui_but_drawstr_without_sep_char(but, drawstr, sizeof(drawstr)); MenuType *mt = NULL; if (but->optype) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6b0b8e8df8f..d61104f094e 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1177,6 +1177,8 @@ uiBut *ui_list_find_mouse_over_ex(const struct ARegion *region, bool ui_but_contains_password(const uiBut *but) ATTR_WARN_UNUSED_RESULT; +size_t ui_but_drawstr_without_sep_char(const uiBut *but, char *str, size_t str_maxlen) + ATTR_NONNULL(1, 2); size_t ui_but_drawstr_len_without_sep_char(const uiBut *but); size_t ui_but_tip_len_only_first_line(const uiBut *but); diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 8534c95b6fd..09429bb6df5 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -23,6 +23,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "DNA_screen_types.h" @@ -553,6 +554,12 @@ size_t ui_but_drawstr_len_without_sep_char(const uiBut *but) return strlen(but->drawstr); } +size_t ui_but_drawstr_without_sep_char(const uiBut *but, char *str, size_t str_maxlen) +{ + size_t str_len_clip = ui_but_drawstr_len_without_sep_char(but); + return BLI_strncpy_rlen(str, but->drawstr, min_zz(str_len_clip + 1, str_maxlen)); +} + size_t ui_but_tip_len_only_first_line(const uiBut *but) { if (but->tip == NULL) { -- cgit v1.2.3 From 4734de1093a1a60621ec6b10e2e56cd09aa3fc64 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 13:17:37 +1000 Subject: Cleanup: correction to unused warning removal This broke building without opensubdiv --- source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 49664323e89..e524564edab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -37,9 +37,10 @@ static bNodeSocketTemplate geo_node_subdivision_surface_out[] = { static void geo_node_subdivision_surface_layout(uiLayout *layout, bContext *UNUSED(C), - PointerRNA *UNUSED(ptr)) + PointerRNA *ptr) { #ifndef WITH_OPENSUBDIV + UNUSED_VARS(ptr); uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); #else uiLayoutSetPropSep(layout, true); -- cgit v1.2.3 From 22ab0159a9754365e2d10a1bc658d4409d084fa6 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 18 Aug 2021 20:30:58 -0700 Subject: Refactor: BLF Without Kerning Modes Simplification of BLF code after removal of kerning modes. See D12262 for more details. Differential Revision: https://developer.blender.org/D12262 Reviewed by Campbell Barton --- source/blender/blenfont/intern/blf_font.c | 104 ++++++--------------- source/blender/blenfont/intern/blf_glyph.c | 14 +-- .../blender/blenfont/intern/blf_internal_types.h | 7 -- 3 files changed, 30 insertions(+), 95 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 36eca3c00e6..9ddc788d2dc 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -308,19 +308,14 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) blf_glyph_cache_release(font); } -static void blf_font_ensure_ascii_kerning(FontBLF *font, - GlyphCacheBLF *gc, - const FT_UInt kern_mode) +static void blf_font_ensure_ascii_kerning(FontBLF *font, GlyphCacheBLF *gc) { - KerningCacheBLF *kc = font->kerning_cache; - - font->kerning_mode = kern_mode; - - if (!kc || kc->mode != kern_mode) { - font->kerning_cache = kc = blf_kerning_cache_find(font); - if (!kc) { - font->kerning_cache = kc = blf_kerning_cache_new(font, gc); - } + if (font->kerning_cache || !FT_HAS_KERNING(font->face)) { + return; + } + font->kerning_cache = blf_kerning_cache_find(font); + if (!font->kerning_cache) { + font->kerning_cache = blf_kerning_cache_new(font, gc); } } @@ -353,28 +348,23 @@ BLI_INLINE GlyphBLF *blf_utf8_next_fast( return g; } -#define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \ - const bool _has_kerning = FT_HAS_KERNING((_font)->face); \ - const FT_UInt _kern_mode = FT_KERNING_DEFAULT; - BLI_INLINE void blf_kerning_step_fast(FontBLF *font, - const FT_UInt kern_mode, const GlyphBLF *g_prev, const GlyphBLF *g, const uint c_prev, const uint c, int *pen_x_p) { - /* `blf_font_ensure_ascii_kerning(font, gc, kern_mode);` must be called before this function. */ - BLI_assert((font->kerning_mode == kern_mode) && (font->kerning_cache != NULL)); + /* `blf_font_ensure_ascii_kerning(font, gc);` must be called before this function. */ + BLI_assert(font->kerning_cache != NULL); - if (g_prev != NULL) { + if (g_prev != NULL && FT_HAS_KERNING(font->face)) { if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { *pen_x_p += font->kerning_cache->ascii_table[c][c_prev]; } else { FT_Vector delta; - if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kern_mode, &delta) == 0) { + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_DEFAULT, &delta) == 0) { *pen_x_p += (int)delta.x >> 6; } } @@ -398,9 +388,7 @@ static void blf_font_draw_ex(FontBLF *font, return; } - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); blf_batch_draw_begin(font); @@ -413,9 +401,7 @@ static void blf_font_draw_ex(FontBLF *font, if (UNLIKELY(g == NULL)) { continue; } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); @@ -449,9 +435,7 @@ static void blf_font_draw_ascii_ex( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); blf_batch_draw_begin(font); @@ -465,9 +449,7 @@ static void blf_font_draw_ascii_ex( continue; } } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); @@ -554,9 +536,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, int chx, chy; int y, x; - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); /* another buffer specific call for color conversion */ @@ -569,9 +549,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font, if (UNLIKELY(g == NULL)) { continue; } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); chx = pen_x + ((int)g->pos[0]); chy = pen_y_basis + g->dims[1]; @@ -685,8 +663,6 @@ void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct Res } static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, - const bool has_kerning, - const FT_UInt kern_mode, const uint c_prev, const uint c, GlyphBLF *g_prev, @@ -700,9 +676,7 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, if (UNLIKELY(g == NULL)) { return false; /* continue the calling loop. */ } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, pen_x); *pen_x += g->advance_i; @@ -720,18 +694,13 @@ size_t blf_font_width_to_strlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - if (has_kerning) { - blf_font_ensure_ascii_kerning(font, gc, kern_mode); - } + blf_font_ensure_ascii_kerning(font, gc); for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i]; i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { g = blf_utf8_next_fast(font, gc, str, &i, &c); - if (blf_font_width_to_strlen_glyph_process( - font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { break; } } @@ -756,11 +725,7 @@ size_t blf_font_width_to_rstrlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - if (has_kerning) { - blf_font_ensure_ascii_kerning(font, gc, kern_mode); - } + blf_font_ensure_ascii_kerning(font, gc); i = BLI_strnlen(str, len); s = BLI_str_find_prev_char_utf8(str, &str[i]); @@ -781,8 +746,7 @@ size_t blf_font_width_to_rstrlen( BLI_assert(i_tmp == i); } - if (blf_font_width_to_strlen_glyph_process( - font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { break; } } @@ -809,14 +773,12 @@ static void blf_font_boundbox_ex(FontBLF *font, size_t i = 0; rctf gbox; - BLF_KERNING_VARS(font, has_kerning, kern_mode); - box->xmin = 32000.0f; box->xmax = -32000.0f; box->ymin = 32000.0f; box->ymax = -32000.0f; - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); while ((i < len) && str[i]) { g = blf_utf8_next_fast(font, gc, str, &i, &c); @@ -827,9 +789,7 @@ static void blf_font_boundbox_ex(FontBLF *font, if (UNLIKELY(g == NULL)) { continue; } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); gbox.xmin = (float)pen_x; gbox.xmax = (float)pen_x + g->advance; @@ -909,9 +869,7 @@ static void blf_font_wrap_apply(FontBLF *font, GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); struct WordWrapVars { int wrap_width; @@ -933,9 +891,7 @@ static void blf_font_wrap_apply(FontBLF *font, if (UNLIKELY(g == NULL)) { continue; } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); /** * Implementation Detail (utf8). @@ -1167,9 +1123,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, return; } - BLF_KERNING_VARS(font, has_kerning, kern_mode); - - blf_font_ensure_ascii_kerning(font, gc, kern_mode); + blf_font_ensure_ascii_kerning(font, gc); while ((i < len) && str[i]) { i_curr = i; @@ -1181,9 +1135,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, if (UNLIKELY(g == NULL)) { continue; } - if (has_kerning) { - blf_kerning_step_fast(font, kern_mode, g_prev, g, c_prev, c, &pen_x); - } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); gbox.xmin = pen_x; gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index c5abc5982e8..5fb69251466 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -57,16 +57,7 @@ KerningCacheBLF *blf_kerning_cache_find(FontBLF *font) { - KerningCacheBLF *p; - - p = (KerningCacheBLF *)font->kerning_caches.first; - while (p) { - if (p->mode == font->kerning_mode) { - return p; - } - p = p->next; - } - return NULL; + return (KerningCacheBLF *)font->kerning_caches.first; } /* Create a new glyph cache for the current kerning mode. */ @@ -75,7 +66,6 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) KerningCacheBLF *kc = MEM_mallocN(sizeof(KerningCacheBLF), __func__); kc->next = NULL; kc->prev = NULL; - kc->mode = font->kerning_mode; GlyphBLF *g_table[KERNING_CACHE_TABLE_SIZE]; for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { @@ -99,7 +89,7 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) continue; } FT_Vector delta; - if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) { + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_DEFAULT, &delta) == 0) { kc->ascii_table[i][j] = (int)delta.x >> 6; } } diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index ece9a5ffae4..caa10b2b125 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -51,10 +51,6 @@ extern BatchBLF g_batch; typedef struct KerningCacheBLF { struct KerningCacheBLF *next, *prev; - - /* kerning mode. */ - FT_UInt mode; - /** * Cache a ascii glyph pairs. Only store the x offset we are interested in, * instead of the full #FT_Vector since it's not used for drawing at the moment. @@ -242,9 +238,6 @@ typedef struct FontBLF { /* freetype2 face. */ FT_Face face; - /* freetype kerning */ - FT_UInt kerning_mode; - /* data for buffer usage (drawing into a texture buffer) */ FontBufInfoBLF buf_info; -- cgit v1.2.3 From cf721942149057684c089c0677c224dbe9d90c52 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 16:57:05 +1000 Subject: Fix T71137: curve minimum twist producing wrong geometry Originally D11886 by @ghaspias with minor edits applied. --- source/blender/blenkernel/intern/curve.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index db0ea71e233..c49788528a4 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2331,17 +2331,21 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl) bevp1 = bevp2 + (bl->nr - 1); bevp0 = bevp1 - 1; - nr = bl->nr; - while (nr--) { + /* The ordinal of the point being adjusted (bevp2). First point is 1. */ - if (nr + 3 > bl->nr) { /* first time and second time, otherwise first point adjusts last */ - vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); - } - else { - minimum_twist_between_two_points(bevp1, bevp0); - } + /* First point is the reference, don't adjust. + * Skip this point in the following loop. */ + if (bl->nr > 0) { + vec_to_quat(bevp2->quat, bevp2->dir, 5, 1); - bevp0 = bevp1; + bevp0 = bevp1; /* bevp0 is unused */ + bevp1 = bevp2; + bevp2++; + } + for (nr = 1; nr < bl->nr; nr++) { + minimum_twist_between_two_points(bevp2, bevp1); + + bevp0 = bevp1; /* bevp0 is unused */ bevp1 = bevp2; bevp2++; } -- cgit v1.2.3 From 4db4123409de6f42a519cd03275d680b3d821298 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Aug 2021 17:55:40 +1000 Subject: Correct assert from 22ab0159a9754365e2d10a1bc658d4409d084fa6 --- source/blender/blenfont/intern/blf_font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 9ddc788d2dc..00d3cfb09eb 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -356,7 +356,7 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, int *pen_x_p) { /* `blf_font_ensure_ascii_kerning(font, gc);` must be called before this function. */ - BLI_assert(font->kerning_cache != NULL); + BLI_assert(font->kerning_cache != NULL || !FT_HAS_KERNING(font->face)); if (g_prev != NULL && FT_HAS_KERNING(font->face)) { if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { -- cgit v1.2.3 From 5b97c00e9fc4e1e5d6cdfa7130eab5aada0e068e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 19 Aug 2021 14:13:45 +0200 Subject: Alembic import: option to always add a cache reader The current behavior of the Alembic importer is to only create a `MeshSequenceCache` modifier or a `Transform Cache` constraint to imported objects if they have some animated properties. Since static objects do not have a cache reader, when reloading files those objects are not updated. Currently, the only way to properly reload a file because of this is to reimport it. This adds an option to the importer to always add a cache reader, even if there is no animated data, to ensure that all objects coming from Alembic archive are linked to them and updated properly upon reloads. Reviewed by: brecht, sybren Ref D10197. --- source/blender/editors/io/io_alembic.c | 10 ++++++++++ source/blender/io/alembic/ABC_alembic.h | 1 + source/blender/io/alembic/intern/abc_reader_curves.cc | 2 +- source/blender/io/alembic/intern/abc_reader_mesh.cc | 4 ++-- source/blender/io/alembic/intern/abc_reader_object.cc | 2 +- source/blender/io/alembic/intern/abc_reader_object.h | 2 ++ source/blender/io/alembic/intern/abc_reader_points.cc | 2 +- source/blender/io/alembic/intern/alembic_capi.cc | 2 ++ 8 files changed, 20 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 12890552b1d..bbff37221e8 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -615,6 +615,7 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr) uiItemR(col, imfptr, "set_frame_range", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "is_sequence", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "always_add_cache_reader", 0, NULL, ICON_NONE); } static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op) @@ -645,6 +646,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence"); const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range"); const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes"); + const bool always_add_cache_reader = RNA_boolean_get(op->ptr, "always_add_cache_reader"); const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job"); int offset = 0; @@ -672,6 +674,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) sequence_len, offset, validate_meshes, + always_add_cache_reader, as_background_job); return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; @@ -721,6 +724,13 @@ void WM_OT_alembic_import(wmOperatorType *ot) "Validate Meshes", "Check imported mesh objects for invalid data (slow)"); + RNA_def_boolean(ot->srna, + "always_add_cache_reader", + false, + "Always Add Cache Reader", + "Add cache modifiers and constraints to imported objects even if they are not " + "animated so that they can be updated when reloading the Alembic archive"); + RNA_def_boolean(ot->srna, "is_sequence", false, diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index 0dbebb1e4c4..0a3a43bb21f 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -97,6 +97,7 @@ bool ABC_import(struct bContext *C, int sequence_len, int offset, bool validate_meshes, + bool always_add_cache_reader, bool as_background_job); struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain, diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc index 8d6605d6973..27ee35d1b39 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.cc +++ b/source/blender/io/alembic/intern/abc_reader_curves.cc @@ -112,7 +112,7 @@ void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele read_curve_sample(cu, m_curves_schema, sample_sel); - if (has_animations(m_curves_schema, m_settings)) { + if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) { addCacheModifier(); } } diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index c05df7f1ff5..77edd4908bd 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -578,7 +578,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec readFaceSetsSample(bmain, mesh, sample_sel); - if (has_animations(m_schema, m_settings)) { + if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) { addCacheModifier(); } } @@ -928,7 +928,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec BKE_mesh_validate(mesh, false, false); } - if (has_animations(m_schema, m_settings)) { + if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) { addCacheModifier(); } } diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index d136d8c3e91..9a5ffd04bd1 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -197,7 +197,7 @@ void AbcObjectReader::setupObjectTransform(const float time) BKE_object_apply_mat4(m_object, transform_from_alembic, true, false); BKE_object_to_mat4(m_object, m_object->obmat); - if (!is_constant) { + if (!is_constant || m_settings->always_add_cache_reader) { bConstraint *con = BKE_constraint_add_for_object( m_object, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE); bTransformCacheConstraint *data = static_cast(con->data); diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h index dacdcf3f722..89590b26b61 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.h +++ b/source/blender/io/alembic/intern/abc_reader_object.h @@ -51,6 +51,7 @@ struct ImportSettings { int read_flag; bool validate_meshes; + bool always_add_cache_reader; CacheFile *cache_file; @@ -65,6 +66,7 @@ struct ImportSettings { sequence_offset(0), read_flag(0), validate_meshes(false), + always_add_cache_reader(false), cache_file(NULL) { } diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc index f7dcba7a0de..3aeacbd14fe 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.cc +++ b/source/blender/io/alembic/intern/abc_reader_points.cc @@ -95,7 +95,7 @@ void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSel m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - if (has_animations(m_schema, m_settings)) { + if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) { addCacheModifier(); } } diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index b94b75b2216..deb945b767c 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -663,6 +663,7 @@ bool ABC_import(bContext *C, int sequence_len, int offset, bool validate_meshes, + bool always_add_cache_reader, bool as_background_job) { /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ @@ -681,6 +682,7 @@ bool ABC_import(bContext *C, job->settings.sequence_len = sequence_len; job->settings.sequence_offset = offset; job->settings.validate_meshes = validate_meshes; + job->settings.always_add_cache_reader = always_add_cache_reader; job->error_code = ABC_NO_ERROR; job->was_cancelled = false; job->archive = nullptr; -- cgit v1.2.3 From 51862c8445c8d5f573d1c86780db9e0972ef14dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 19 Aug 2021 14:34:01 +0200 Subject: Cycles: experimental integration of Alembic procedural in viewport rendering This patch exposes the Cycles Alembic Procedural through the MeshSequenceCache modifier in order to use and test it from Blender. To enable it, one has to switch the render feature set to experimental and activate the Procedural in the modifier. An Alembic Procedural is then created for each CacheFile from Blender set to use the Procedural, and each Blender object having a MeshSequenceCache modifier is added to list of objects of the right procedural. The procedural's parameters derive from the CacheFile's properties which are already exposed in the UI through the modifier, although more Cycles specific options might be added in the future. As there is currently no cache controls and since we load all the data at the beginning of the render session, the procedural is only available during viewport renders at the moment. When an Alembic procedural is rendered, data from the archive are not read on the Blender side. If a Cycles render is not active and the CacheFile is set to use the Cycles Procedural, bounding boxes are used to display the objects in the scene as a signal that the objects are not processed by Blender anymore. This is standard in other DCCs. However this does not reduce the memory usage from Blender as the Alembic data was already loaded either during an import or during a .blend file read. This is mostly a hack to test the Cycles Alembic procedural until we have a better Blender side mechanism for letting renderers load their own geometry, which will be based on import and export settings on Collections (T68933). Ref T79174, D3089 Reviewed By: brecht, sybren Maniphest Tasks: T79174 Differential Revision: https://developer.blender.org/D10197 --- source/blender/blenkernel/BKE_cachefile.h | 10 ++++ source/blender/blenkernel/BKE_modifier.h | 8 +++- source/blender/blenkernel/BKE_object.h | 5 +- source/blender/blenkernel/BKE_scene.h | 4 ++ source/blender/blenkernel/intern/cachefile.c | 18 ++++++++ source/blender/blenkernel/intern/constraint.c | 5 ++ source/blender/blenkernel/intern/modifier.c | 4 +- source/blender/blenkernel/intern/object.c | 7 ++- source/blender/blenkernel/intern/scene.c | 18 ++++++++ .../intern/builder/deg_builder_relations.cc | 3 +- .../editors/interface/interface_templates.c | 25 ++++++++++ source/blender/editors/render/render_update.c | 14 ++++++ source/blender/makesdna/DNA_cachefile_types.h | 11 ++++- source/blender/makesrna/intern/rna_cachefile.c | 17 +++++++ source/blender/makesrna/intern/rna_render.c | 6 +++ source/blender/makesrna/intern/rna_scene.c | 10 ++++ source/blender/modifiers/intern/MOD_build.c | 4 +- source/blender/modifiers/intern/MOD_cloth.c | 4 +- source/blender/modifiers/intern/MOD_collision.c | 4 +- source/blender/modifiers/intern/MOD_displace.c | 4 +- source/blender/modifiers/intern/MOD_dynamicpaint.c | 4 +- source/blender/modifiers/intern/MOD_explode.c | 4 +- source/blender/modifiers/intern/MOD_fluid.c | 4 +- source/blender/modifiers/intern/MOD_meshcache.c | 4 +- .../modifiers/intern/MOD_meshsequencecache.c | 53 +++++++++++++++++++++- source/blender/modifiers/intern/MOD_softbody.c | 4 +- source/blender/modifiers/intern/MOD_surface.c | 4 +- .../modifiers/intern/MOD_volume_displace.cc | 2 +- source/blender/modifiers/intern/MOD_warp.c | 4 +- source/blender/modifiers/intern/MOD_wave.c | 4 +- source/blender/modifiers/intern/MOD_weightvgedit.c | 4 +- source/blender/modifiers/intern/MOD_weightvgmix.c | 4 +- .../modifiers/intern/MOD_weightvgproximity.c | 4 +- source/blender/render/RE_engine.h | 7 +++ source/blender/render/intern/engine.c | 13 ++++++ 35 files changed, 272 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index a6b2aa8540a..58d876b184b 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -32,6 +32,7 @@ struct CacheReader; struct Depsgraph; struct Main; struct Object; +struct Scene; void BKE_cachefiles_init(void); void BKE_cachefiles_exit(void); @@ -60,6 +61,15 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file, const char *object_path); void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader); +/* Determine whether the CacheFile should use a render engine procedural. If so, data is not read + * from the file and bouding boxes are used to represent the objects in the Scene. Render engines + * will receive the bounding box as a placeholder but can instead load the data directly if they + * support it. + */ +bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, + struct Scene *scene, + const int dag_eval_mode); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 0b4e1191956..c5f309570cd 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -319,8 +319,10 @@ typedef struct ModifierTypeInfo { * changes. * * This function is optional (assumes false if not present). + * + * The dag_eval_mode should be of type eEvaluationMode. */ - bool (*dependsOnTime)(struct ModifierData *md); + bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, const int dag_eval_mode); /** * True when a deform modifier uses normals, the requiredDataMask @@ -425,7 +427,9 @@ void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target) void BKE_modifier_copydata_ex(struct ModifierData *md, struct ModifierData *target, const int flag); -bool BKE_modifier_depends_ontime(struct ModifierData *md); +bool BKE_modifier_depends_ontime(struct Scene *scene, + struct ModifierData *md, + int dag_eval_mode); bool BKE_modifier_supports_mapping(struct ModifierData *md); bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md); bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 4724e6dfab6..a823602e341 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -401,7 +401,10 @@ void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Obj struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot); -bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md); +bool BKE_object_modifier_use_time(struct Scene *scene, + struct Object *ob, + struct ModifierData *md, + int dag_eval_mode); bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 6d58e165ea3..83ce5e72794 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -174,6 +174,10 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene); bool BKE_scene_uses_blender_workbench(const struct Scene *scene); bool BKE_scene_uses_cycles(const struct Scene *scene); +/* Return whether the Cycles experimental feature is enabled. It is invalid to call without first + * ensuring that Cycles is the active render engine (e.g. with BKE_scene_uses_cycles). */ +bool BKE_scene_uses_cycles_experimental_features(struct Scene *scene); + void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src); void BKE_scene_disable_color_management(struct Scene *scene); diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 75180de94d8..8dd28c889f5 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -49,6 +49,8 @@ #include "DEG_depsgraph_query.h" +#include "RE_engine.h" + #include "BLO_read_write.h" #ifdef WITH_ALEMBIC @@ -409,3 +411,19 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c const float frame = (cache_file->override_frame ? cache_file->frame : time); return cache_file->is_sequence ? frame : frame / fps - time_offset; } + +bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, + Scene *scene, + const int dag_eval_mode) +{ + RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine); + + if (cache_file->type != CACHEFILE_TYPE_ALEMBIC || + !RE_engine_supports_alembic_procedural(render_engine_type, scene)) { + return false; + } + + /* The render time procedural is only enabled during viewport rendering. */ + const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER; + return cache_file->use_render_procedural && !is_final_render; +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 4b26022039e..30aa22387d0 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5430,6 +5430,11 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa return; } + /* Do not process data if using a render time procedural. */ + if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(cob->depsgraph))) { + return; + } + const float frame = DEG_get_ctime(cob->depsgraph); const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 2088c4268e6..821ca7b98b3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -249,11 +249,11 @@ bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md) return false; } -bool BKE_modifier_depends_ontime(ModifierData *md) +bool BKE_modifier_depends_ontime(Scene *scene, ModifierData *md, const int dag_eval_mode) { const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - return mti->dependsOnTime && mti->dependsOnTime(md); + return mti->dependsOnTime && mti->dependsOnTime(scene, md, dag_eval_mode); } bool BKE_modifier_supports_mapping(ModifierData *md) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 23b9dca8371..86db4b6ace8 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -5411,9 +5411,12 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) return tree; } -bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) +bool BKE_object_modifier_use_time(Scene *scene, + Object *ob, + ModifierData *md, + const int dag_eval_mode) { - if (BKE_modifier_depends_ontime(md)) { + if (BKE_modifier_depends_ontime(scene, md, dag_eval_mode)) { return true; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 5ecd9b7283e..3fe00adc4d5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -109,6 +109,8 @@ #include "RE_engine.h" +#include "RNA_access.h" + #include "SEQ_edit.h" #include "SEQ_iterator.h" #include "SEQ_modifier.h" @@ -2938,6 +2940,22 @@ bool BKE_scene_uses_cycles(const Scene *scene) return STREQ(scene->r.engine, RE_engine_id_CYCLES); } +/* This enumeration has to match the one defined in the Cycles addon. */ +typedef enum eCyclesFeatureSet { + CYCLES_FEATURES_SUPPORTED = 0, + CYCLES_FEATURES_EXPERIMENTAL = 1, +} eCyclesFeatureSet; + +/* We cannot use const as RNA_id_pointer_create is not using a const ID. */ +bool BKE_scene_uses_cycles_experimental_features(Scene *scene) +{ + BLI_assert(BKE_scene_uses_cycles(scene)); + PointerRNA scene_ptr; + RNA_id_pointer_create(&scene->id, &scene_ptr); + PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles"); + return RNA_enum_get(&cycles_ptr, "feature_set") == CYCLES_FEATURES_EXPERIMENTAL; +} + void BKE_scene_base_flag_to_objects(ViewLayer *view_layer) { Base *base = view_layer->object_bases.first; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 7da3d2e25f0..d88e9bc9c04 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -118,6 +118,7 @@ #include "intern/node/deg_node_operation.h" #include "intern/node/deg_node_time.h" +#include "intern/depsgraph.h" #include "intern/depsgraph_relation.h" #include "intern/depsgraph_type.h" @@ -2095,7 +2096,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); mti->updateDepsgraph(md, &ctx); } - if (BKE_object_modifier_use_time(object, md)) { + if (BKE_object_modifier_use_time(scene_, object, md, graph_->mode)) { TimeSourceKey time_src_key; add_relation(time_src_key, obdata_ubereval_key, "Time Source"); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 47ff0c9fd3c..f0d50985237 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -84,6 +84,8 @@ #include "ED_screen.h" #include "ED_undo.h" +#include "RE_engine.h" + #include "RNA_access.h" #include "WM_api.h" @@ -6463,6 +6465,29 @@ void uiTemplateCacheFile(uiLayout *layout, row = uiLayoutRow(layout, false); uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE); + /* Only enable render procedural option if the active engine supports it. */ + const struct RenderEngineType *engine_type = CTX_data_engine_type(C); + + Scene *scene = CTX_data_scene(C); + const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, scene); + + if (!engine_supports_procedural) { + row = uiLayoutRow(layout, false); + /* For Cycles, verify that experimental features are enabled. */ + if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { + uiItemL(row, + "The Cycles Alembic Procedural is only available with the experimental feature set", + ICON_INFO); + } + else { + uiItemL(row, "The active render engine does not have an Alembic Procedural", ICON_INFO); + } + } + + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, engine_supports_procedural); + uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE); + row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); sub = uiLayoutRow(row, true); uiLayoutSetPropDecorate(sub, false); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index fb9d11feb63..6db148eb4e1 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -23,6 +23,7 @@ #include #include +#include "DNA_cachefile_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -204,6 +205,19 @@ void ED_render_engine_changed(Main *bmain, const bool update_scene_data) ntreeCompositUpdateRLayers(scene->nodetree); } } + + /* Update CacheFiles to ensure that procedurals are properly taken into account. */ + LISTBASE_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { + /* Only update cachefiles which are set to use a render procedural. We do not use + * BKE_cachefile_uses_render_procedural here as we need to update regardless of the current + * engine or its settings. */ + if (cachefile->use_render_procedural) { + DEG_id_tag_update(&cachefile->id, ID_RECALC_COPY_ON_WRITE); + /* Rebuild relations so that modifiers are reconnected to or disconnected from the cachefile. + */ + DEG_relations_tag_update(bmain); + } + } } void ED_render_view_layer_changed(Main *bmain, bScreen *screen) diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index b38c7827ea5..ae4ade49be1 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -87,14 +87,21 @@ typedef struct CacheFile { /** The frame offset to subtract. */ float frame_offset; + char _pad[4]; + /** Animation flag. */ short flag; - short draw_flag; /* UNUSED */ /* eCacheFileType enum. */ char type; - char _pad[2]; + /** Do not load data from the cache file and display objects in the scene as boxes, Cycles will + * load objects directly from the CacheFile. Other render engines which can load Alembic data + * directly can take care of rendering it themselves. + */ + char use_render_procedural; + + char _pad1[7]; char velocity_unit; /* Name of the velocity property in the archive. */ diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index b93f494072c..cb0a490417d 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -37,6 +37,7 @@ # include "BKE_cachefile.h" # include "DEG_depsgraph.h" +# include "DEG_depsgraph_build.h" # include "WM_api.h" # include "WM_types.h" @@ -53,6 +54,12 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); } +static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_CacheFile_update(bmain, scene, ptr); + DEG_relations_tag_update(bmain); +} + static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { CacheFile *cache_file = (CacheFile *)ptr->data; @@ -105,6 +112,16 @@ static void rna_def_cachefile(BlenderRNA *brna) prop, "Sequence", "Whether the cache is separated in a series of files"); RNA_def_property_update(prop, 0, "rna_CacheFile_update"); + prop = RNA_def_property(srna, "use_render_procedural", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text( + prop, + "Use Render Engine Procedural", + "Display boxes in the viewport as placeholders for the objects, Cycles will use a " + "procedural to load the objects during viewport rendering in experimental mode, " + "other render engines will also receive a placeholder and should take care of loading the " + "Alembic data themselves if possible"); + RNA_def_property_update(prop, 0, "rna_CacheFile_dependency_update"); + /* ----------------- For Scene time ------------------- */ prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 73924c45d52..4400d198b4a 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -896,6 +896,12 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Use Stereo Viewport", "Support rendering stereo 3D viewport"); + prop = RNA_def_property(srna, "bl_use_alembic_procedural", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_ALEMBIC_PROCEDURAL); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_ui_text( + prop, "Use Alembic Procedural", "Support loading Alembic data at render time"); + RNA_define_verify_sdna(1); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index f0a1508fb5f..9d158761a21 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -616,6 +616,7 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = { # include "BLI_string_utils.h" # include "DNA_anim_types.h" +# include "DNA_cachefile_types.h" # include "DNA_color_types.h" # include "DNA_mesh_types.h" # include "DNA_node_types.h" @@ -1619,6 +1620,11 @@ static void rna_RenderSettings_engine_update(Main *bmain, ED_render_engine_changed(bmain, true); } +static void rna_Scene_update_render_engine(Main *bmain) +{ + ED_render_engine_changed(bmain, true); +} + static bool rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr)) { return (BLI_listbase_count(&R_engines) > 1); @@ -7836,6 +7842,10 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE, NULL); RNA_def_property_update(prop, NC_SCENE, "rna_Scene_volume_update"); + func = RNA_def_function(srna, "update_render_engine", "rna_Scene_update_render_engine"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_MAIN); + RNA_def_function_ui_description(func, "Trigger a render engine update"); + /* Statistics */ func = RNA_def_function(srna, "statistics", "rna_Scene_statistics_string_get"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 52f21e3d3d0..a344a15b0c1 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -61,7 +61,9 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(bmd, DNA_struct_default_get(BuildModifierData), modifier); } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 4487adcfdda..fa2f70e1a9c 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -220,7 +220,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla tclmd->solver_result = NULL; } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 5dd57469914..e7d5fe056c5 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -95,7 +95,9 @@ static void freeData(ModifierData *md) } } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index a7ac9f618af..07da18f990d 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -95,7 +95,9 @@ static void requiredDataMask(Object *UNUSED(ob), } } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { DisplaceModifierData *dmd = (DisplaceModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 8b1d541d45d..77ae5c4b6f1 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -155,7 +155,9 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index bf197dca7e5..493b59b3a1a 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -86,7 +86,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla temd->facepa = NULL; } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c index 36d2ab2a11a..a14d582063a 100644 --- a/source/blender/modifiers/intern/MOD_fluid.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -132,7 +132,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * #endif /* WITH_FLUID */ } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index e0507320628..6ef64ad8bc9 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -63,7 +63,9 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(mcmd, DNA_struct_default_get(MeshCacheModifierData), modifier); } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA); diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 3e6081e0a18..2aa76c18c83 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -20,6 +20,7 @@ #include +#include "BLI_math_vector.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -39,6 +40,8 @@ #include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_lib_query.h" +#include "BKE_mesh.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -118,6 +121,44 @@ static bool isDisabled(const struct Scene *UNUSED(scene), return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); } +static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh) +{ + BoundBox *bb = BKE_object_boundbox_get(object); + Mesh *result = BKE_mesh_new_nomain_from_template(org_mesh, 8, 0, 0, 24, 6); + + MVert *mvert = result->mvert; + for (int i = 0; i < 8; ++i) { + copy_v3_v3(mvert[i].co, bb->vec[i]); + } + + /* See DNA_object_types.h for the diagram showing the order of the vertices for a BoundBox. */ + static unsigned int loops_v[6][4] = { + {0, 4, 5, 1}, + {4, 7, 6, 5}, + {7, 3, 2, 6}, + {3, 0, 1, 2}, + {1, 5, 6, 2}, + {3, 7, 4, 0}, + }; + + MLoop *mloop = result->mloop; + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 4; ++j, ++mloop) { + mloop->v = loops_v[i][j]; + } + } + + MPoly *mpoly = result->mpoly; + for (int i = 0; i < 6; ++i) { + mpoly[i].loopstart = i * 4; + mpoly[i].totloop = 4; + } + + BKE_mesh_calc_edges(result, false, false); + + return result; +} + static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { #if defined(WITH_USD) || defined(WITH_ALEMBIC) @@ -143,6 +184,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } } + /* Do not process data if using a render procedural, return a box instead for displaying in the + * viewport. */ + if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(ctx->depsgraph))) { + return generate_bounding_box_mesh(ctx->object, org_mesh); + } + /* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we * must return the mesh as-is instead of deforming it. */ if (ctx->flag & MOD_APPLY_ORCO) { @@ -228,11 +275,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * #endif } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode) { #if defined(WITH_USD) || defined(WITH_ALEMBIC) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - return (mcmd->cache_file != NULL); + /* Do not evaluate animations if using the render engine procedural. */ + return (mcmd->cache_file != NULL) && + !BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode); #else UNUSED_VARS(md); return false; diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index d7d2f948955..4187f9087a0 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -62,7 +62,9 @@ static void deformVerts(ModifierData *UNUSED(md), ctx->depsgraph, scene, ctx->object, DEG_get_ctime(ctx->depsgraph), vertexCos, numVerts); } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index bfd4cd81803..3f2d0a06db8 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -98,7 +98,9 @@ static void freeData(ModifierData *md) } } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index af4b31d6bfc..dfd3fdd80f8 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -95,7 +95,7 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "texture"); } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *md, const int UNUSED(dag_eval_mode)) { VolumeDisplaceModifierData *vdmd = reinterpret_cast(md); if (vdmd->texture) { diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 3bebc52c503..25e33b22bde 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -116,7 +116,9 @@ static void matrix_from_obj_pchan(float mat[4][4], } } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { WarpModifierData *wmd = (WarpModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index cf4c195c66d..03f8e3a1dfb 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -70,7 +70,9 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WaveModifierData), modifier); } -static bool dependsOnTime(ModifierData *UNUSED(md)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *UNUSED(md), + const int UNUSED(dag_eval_mode)) { return true; } diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 093fa118ee0..a9d01c64ff1 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -112,7 +112,9 @@ static void requiredDataMask(Object *UNUSED(ob), /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 7aae089fa18..b369b82ebb7 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -154,7 +154,9 @@ static void requiredDataMask(Object *UNUSED(ob), /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 6e78774269a..7ee19e1c537 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -362,7 +362,9 @@ static void requiredDataMask(Object *UNUSED(ob), /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(ModifierData *md) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h index 6b2861bbefd..dfc0d5d0e9f 100644 --- a/source/blender/render/RE_engine.h +++ b/source/blender/render/RE_engine.h @@ -66,6 +66,7 @@ extern "C" { #define RE_USE_GPU_CONTEXT 512 #define RE_USE_CUSTOM_FREESTYLE 1024 #define RE_USE_NO_IMAGE_SAVE 2048 +#define RE_USE_ALEMBIC_PROCEDURAL 4096 /* RenderEngine.flag */ #define RE_ENGINE_ANIMATION 1 @@ -235,6 +236,12 @@ void RE_engines_register(RenderEngineType *render_type); bool RE_engine_is_opengl(RenderEngineType *render_type); +/** + * Return true if the RenderEngineType has native support for direct loading of Alembic data. For + * Cycles, this also checks that the experimental feature set is enabled. + */ +bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene); + RenderEngineType *RE_engines_find(const char *idname); rcti *RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free); diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 657cd1f606b..75b3f2db249 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -128,6 +128,19 @@ bool RE_engine_is_opengl(RenderEngineType *render_type) return (render_type->draw_engine != NULL) && DRW_engine_render_support(render_type->draw_engine); } +bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene) +{ + if ((render_type->flag & RE_USE_ALEMBIC_PROCEDURAL) == 0) { + return false; + } + + if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { + return false; + } + + return true; +} + /* Create, Free */ RenderEngine *RE_engine_create(RenderEngineType *type) -- cgit v1.2.3 From d5776f48297e79467407164fe9cb4042dbeccb31 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Aug 2021 11:12:37 +0200 Subject: LibOverride: Tag all embedded IDs RNA opinters as overridablei, part II. Not sure how I failed to include those files in rBe5f8db92b696... --- source/blender/makesrna/intern/rna_light.c | 1 + source/blender/makesrna/intern/rna_linestyle.c | 1 + source/blender/makesrna/intern/rna_simulation.c | 1 + source/blender/makesrna/intern/rna_texture.c | 1 + source/blender/makesrna/intern/rna_world.c | 1 + 5 files changed, 5 insertions(+) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index 0593db0dd56..8bec337885e 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -188,6 +188,7 @@ static void rna_def_light(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based lights"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index ca97f2c9a55..8cd1ac0d963 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -2189,6 +2189,7 @@ static void rna_def_linestyle(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based shaders"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_simulation.c b/source/blender/makesrna/intern/rna_simulation.c index cc9a4bec2e7..6f5041c9ed1 100644 --- a/source/blender/makesrna/intern/rna_simulation.c +++ b/source/blender/makesrna/intern/rna_simulation.c @@ -43,6 +43,7 @@ static void rna_def_simulation(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree defining the simulation"); /* common */ diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 128f1cb1e21..5a74cfa9964 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1642,6 +1642,7 @@ static void rna_def_texture(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based textures"); RNA_def_property_update(prop, 0, "rna_Texture_nodes_update"); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index a66e3090548..826e6d21c36 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -237,6 +237,7 @@ void RNA_def_world(BlenderRNA *brna) prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_clear_flag(prop, PROP_PTR_NO_OWNERSHIP); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based worlds"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); -- cgit v1.2.3 From 0f49e4832cf2afad437aa16ebbbe37191de9af71 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Aug 2021 11:13:55 +0200 Subject: Cleanup: Blendwrite: Move code deciding if an ID should be written out of ID callbacks. This was not really useful, and added estra useless steps in case and ID should not actually be written. Further more, it prevented clearing the usercount on write, which can be cause a false positive 'chanhged' detection in undo/redo case. --- source/blender/blenkernel/intern/action.c | 21 ++-- source/blender/blenkernel/intern/armature.c | 31 +++--- source/blender/blenkernel/intern/brush.c | 73 +++++++------ source/blender/blenkernel/intern/cachefile.c | 21 ++-- source/blender/blenkernel/intern/camera.c | 19 ++-- source/blender/blenkernel/intern/collection.c | 23 ++-- source/blender/blenkernel/intern/curve.c | 69 ++++++------ source/blender/blenkernel/intern/font.c | 27 +++-- source/blender/blenkernel/intern/gpencil.c | 71 ++++++------ source/blender/blenkernel/intern/hair.c | 49 +++++---- source/blender/blenkernel/intern/image.c | 57 +++++----- source/blender/blenkernel/intern/key.c | 41 ++++--- source/blender/blenkernel/intern/lattice.c | 33 +++--- source/blender/blenkernel/intern/light.c | 31 +++--- source/blender/blenkernel/intern/lightprobe.c | 15 ++- source/blender/blenkernel/intern/linestyle.c | 35 +++--- source/blender/blenkernel/intern/mask.c | 57 +++++----- source/blender/blenkernel/intern/material.c | 39 ++++--- source/blender/blenkernel/intern/mball.c | 41 ++++--- source/blender/blenkernel/intern/mesh.c | 143 ++++++++++++------------- source/blender/blenkernel/intern/movieclip.c | 45 ++++---- source/blender/blenkernel/intern/node.cc | 21 ++-- source/blender/blenkernel/intern/object.c | 108 +++++++++---------- source/blender/blenkernel/intern/paint.c | 22 ++-- source/blender/blenkernel/intern/particle.c | 85 ++++++++------- source/blender/blenkernel/intern/pointcloud.cc | 41 ++++--- source/blender/blenkernel/intern/screen.c | 18 ++-- source/blender/blenkernel/intern/simulation.cc | 25 +++-- source/blender/blenkernel/intern/sound.c | 29 +++-- source/blender/blenkernel/intern/speaker.c | 15 ++- source/blender/blenkernel/intern/text.c | 3 - source/blender/blenkernel/intern/texture.c | 33 +++--- source/blender/blenkernel/intern/volume.cc | 31 +++--- source/blender/blenkernel/intern/world.c | 29 +++-- source/blender/blenloader/intern/writefile.c | 8 ++ 35 files changed, 687 insertions(+), 722 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d55f023d209..981815f400a 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -186,22 +186,21 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data) static void action_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bAction *act = (bAction *)id; - if (act->id.us > 0 || BLO_write_is_undo(writer)) { - BLO_write_id_struct(writer, bAction, id_address, &act->id); - BKE_id_blend_write(writer, &act->id); - BKE_fcurve_blend_write(writer, &act->curves); + BLO_write_id_struct(writer, bAction, id_address, &act->id); + BKE_id_blend_write(writer, &act->id); - LISTBASE_FOREACH (bActionGroup *, grp, &act->groups) { - BLO_write_struct(writer, bActionGroup, grp); - } + BKE_fcurve_blend_write(writer, &act->curves); - LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { - BLO_write_struct(writer, TimeMarker, marker); - } + LISTBASE_FOREACH (bActionGroup *, grp, &act->groups) { + BLO_write_struct(writer, bActionGroup, grp); + } - BKE_previewimg_blend_write(writer, act->preview); + LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { + BLO_write_struct(writer, TimeMarker, marker); } + + BKE_previewimg_blend_write(writer, act->preview); } static void action_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 1f02b084534..87320c88b1b 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -212,25 +212,24 @@ static void write_bone(BlendWriter *writer, Bone *bone) static void armature_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bArmature *arm = (bArmature *)id; - if (arm->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - arm->bonehash = NULL; - arm->edbo = NULL; - /* Must always be cleared (armatures don't have their own edit-data). */ - arm->needs_flush_to_id = 0; - arm->act_edbone = NULL; - BLO_write_id_struct(writer, bArmature, id_address, &arm->id); - BKE_id_blend_write(writer, &arm->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + arm->bonehash = NULL; + arm->edbo = NULL; + /* Must always be cleared (armatures don't have their own edit-data). */ + arm->needs_flush_to_id = 0; + arm->act_edbone = NULL; - if (arm->adt) { - BKE_animdata_blend_write(writer, arm->adt); - } + BLO_write_id_struct(writer, bArmature, id_address, &arm->id); + BKE_id_blend_write(writer, &arm->id); - /* Direct data */ - LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - write_bone(writer, bone); - } + if (arm->adt) { + BKE_animdata_blend_write(writer, arm->adt); + } + + /* Direct data */ + LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { + write_bone(writer, bone); } } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 3418e37642c..7b81187be21 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -202,48 +202,47 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data) static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Brush *brush = (Brush *)id; - if (brush->id.us > 0 || BLO_write_is_undo(writer)) { - BLO_write_id_struct(writer, Brush, id_address, &brush->id); - BKE_id_blend_write(writer, &brush->id); - if (brush->curve) { - BKE_curvemapping_blend_write(writer, brush->curve); - } + BLO_write_id_struct(writer, Brush, id_address, &brush->id); + BKE_id_blend_write(writer, &brush->id); - if (brush->gpencil_settings) { - BLO_write_struct(writer, BrushGpencilSettings, brush->gpencil_settings); + if (brush->curve) { + BKE_curvemapping_blend_write(writer, brush->curve); + } - if (brush->gpencil_settings->curve_sensitivity) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_sensitivity); - } - if (brush->gpencil_settings->curve_strength) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_strength); - } - if (brush->gpencil_settings->curve_jitter) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_jitter); - } - if (brush->gpencil_settings->curve_rand_pressure) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_pressure); - } - if (brush->gpencil_settings->curve_rand_strength) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_strength); - } - if (brush->gpencil_settings->curve_rand_uv) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_uv); - } - if (brush->gpencil_settings->curve_rand_hue) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_hue); - } - if (brush->gpencil_settings->curve_rand_saturation) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_saturation); - } - if (brush->gpencil_settings->curve_rand_value) { - BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_value); - } + if (brush->gpencil_settings) { + BLO_write_struct(writer, BrushGpencilSettings, brush->gpencil_settings); + + if (brush->gpencil_settings->curve_sensitivity) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_sensitivity); } - if (brush->gradient) { - BLO_write_struct(writer, ColorBand, brush->gradient); + if (brush->gpencil_settings->curve_strength) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_strength); } + if (brush->gpencil_settings->curve_jitter) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_jitter); + } + if (brush->gpencil_settings->curve_rand_pressure) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_pressure); + } + if (brush->gpencil_settings->curve_rand_strength) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_strength); + } + if (brush->gpencil_settings->curve_rand_uv) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_uv); + } + if (brush->gpencil_settings->curve_rand_hue) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_hue); + } + if (brush->gpencil_settings->curve_rand_saturation) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_saturation); + } + if (brush->gpencil_settings->curve_rand_value) { + BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_value); + } + } + if (brush->gradient) { + BLO_write_struct(writer, ColorBand, brush->gradient); } } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 8dd28c889f5..4a60564b4a1 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -97,19 +97,18 @@ static void cache_file_free_data(ID *id) static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address) { CacheFile *cache_file = (CacheFile *)id; - if (cache_file->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - BLI_listbase_clear(&cache_file->object_paths); - cache_file->handle = NULL; - memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath)); - cache_file->handle_readers = NULL; - BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id); - BKE_id_blend_write(writer, &cache_file->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + BLI_listbase_clear(&cache_file->object_paths); + cache_file->handle = NULL; + memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath)); + cache_file->handle_readers = NULL; - if (cache_file->adt) { - BKE_animdata_blend_write(writer, cache_file->adt); - } + BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id); + BKE_id_blend_write(writer, &cache_file->id); + + if (cache_file->adt) { + BKE_animdata_blend_write(writer, cache_file->adt); } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 5172b067eba..46b079fb42e 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -122,18 +122,17 @@ static void camera_foreach_id(ID *id, LibraryForeachIDData *data) static void camera_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Camera *cam = (Camera *)id; - if (cam->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, Camera, id_address, &cam->id); - BKE_id_blend_write(writer, &cam->id); - if (cam->adt) { - BKE_animdata_blend_write(writer, cam->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Camera, id_address, &cam->id); + BKE_id_blend_write(writer, &cam->id); - LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) { - BLO_write_struct(writer, CameraBGImage, bgpic); - } + if (cam->adt) { + BKE_animdata_blend_write(writer, cam->adt); + } + + LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) { + BLO_write_struct(writer, CameraBGImage, bgpic); } } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index b62e33ff564..d36e9b67d00 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -214,20 +214,19 @@ void BKE_collection_blend_write_nolib(BlendWriter *writer, Collection *collectio static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Collection *collection = (Collection *)id; - if (collection->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ - collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE; - collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED; - collection->tag = 0; - BLI_listbase_clear(&collection->object_cache); - BLI_listbase_clear(&collection->object_cache_instanced); - BLI_listbase_clear(&collection->parents); - /* write LibData */ - BLO_write_id_struct(writer, Collection, id_address, &collection->id); + /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ + collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE; + collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE_INSTANCED; + collection->tag = 0; + BLI_listbase_clear(&collection->object_cache); + BLI_listbase_clear(&collection->object_cache_instanced); + BLI_listbase_clear(&collection->parents); - BKE_collection_blend_write_nolib(writer, collection); - } + /* write LibData */ + BLO_write_id_struct(writer, Collection, id_address, &collection->id); + + BKE_collection_blend_write_nolib(writer, collection); } #ifdef USE_COLLECTION_COMPAT_28 diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index c49788528a4..397838e6904 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -146,51 +146,50 @@ static void curve_foreach_id(ID *id, LibraryForeachIDData *data) static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Curve *cu = (Curve *)id; - if (cu->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - cu->editnurb = NULL; - cu->editfont = NULL; - cu->batch_cache = NULL; - /* write LibData */ - BLO_write_id_struct(writer, Curve, id_address, &cu->id); - BKE_id_blend_write(writer, &cu->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + cu->editnurb = NULL; + cu->editfont = NULL; + cu->batch_cache = NULL; - /* direct data */ - BLO_write_pointer_array(writer, cu->totcol, cu->mat); - if (cu->adt) { - BKE_animdata_blend_write(writer, cu->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Curve, id_address, &cu->id); + BKE_id_blend_write(writer, &cu->id); - if (cu->vfont) { - BLO_write_raw(writer, cu->len + 1, cu->str); - BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo); - BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb); + /* direct data */ + BLO_write_pointer_array(writer, cu->totcol, cu->mat); + if (cu->adt) { + BKE_animdata_blend_write(writer, cu->adt); + } + + if (cu->vfont) { + BLO_write_raw(writer, cu->len + 1, cu->str); + BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo); + BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb); + } + else { + /* is also the order of reading */ + LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { + BLO_write_struct(writer, Nurb, nu); } - else { - /* is also the order of reading */ - LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - BLO_write_struct(writer, Nurb, nu); + LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { + if (nu->type == CU_BEZIER) { + BLO_write_struct_array(writer, BezTriple, nu->pntsu, nu->bezt); } - LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - if (nu->type == CU_BEZIER) { - BLO_write_struct_array(writer, BezTriple, nu->pntsu, nu->bezt); + else { + BLO_write_struct_array(writer, BPoint, nu->pntsu * nu->pntsv, nu->bp); + if (nu->knotsu) { + BLO_write_float_array(writer, KNOTSU(nu), nu->knotsu); } - else { - BLO_write_struct_array(writer, BPoint, nu->pntsu * nu->pntsv, nu->bp); - if (nu->knotsu) { - BLO_write_float_array(writer, KNOTSU(nu), nu->knotsu); - } - if (nu->knotsv) { - BLO_write_float_array(writer, KNOTSV(nu), nu->knotsv); - } + if (nu->knotsv) { + BLO_write_float_array(writer, KNOTSV(nu), nu->knotsv); } } } + } - if (cu->bevel_profile != NULL) { - BKE_curveprofile_blend_write(writer, cu->bevel_profile); - } + if (cu->bevel_profile != NULL) { + BKE_curveprofile_blend_write(writer, cu->bevel_profile); } } diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 72add476bfe..c1765967238 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -126,23 +126,22 @@ static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_addres { VFont *vf = (VFont *)id; const bool is_undo = BLO_write_is_undo(writer); - if (vf->id.us > 0 || is_undo) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - vf->data = NULL; - vf->temp_pf = NULL; - - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) { - vf->packedfile = NULL; - } - /* write LibData */ - BLO_write_id_struct(writer, VFont, id_address, &vf->id); - BKE_id_blend_write(writer, &vf->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + vf->data = NULL; + vf->temp_pf = NULL; - /* direct data */ - BKE_packedfile_blend_write(writer, vf->packedfile); + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) { + vf->packedfile = NULL; } + + /* write LibData */ + BLO_write_id_struct(writer, VFont, id_address, &vf->id); + BKE_id_blend_write(writer, &vf->id); + + /* direct data */ + BKE_packedfile_blend_write(writer, vf->packedfile); } static void vfont_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f566e18fb2f..9cdb7395925 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -150,47 +150,46 @@ static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data) static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bGPdata *gpd = (bGPdata *)id; - if (gpd->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ - /* XXX not sure why the whole run-time data is not cleared in reading code, - * for now mimicking it here. */ - gpd->runtime.sbuffer = NULL; - gpd->runtime.sbuffer_used = 0; - gpd->runtime.sbuffer_size = 0; - gpd->runtime.tot_cp_points = 0; - /* write gpd data block to file */ - BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id); - BKE_id_blend_write(writer, &gpd->id); + /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ + /* XXX not sure why the whole run-time data is not cleared in reading code, + * for now mimicking it here. */ + gpd->runtime.sbuffer = NULL; + gpd->runtime.sbuffer_used = 0; + gpd->runtime.sbuffer_size = 0; + gpd->runtime.tot_cp_points = 0; - if (gpd->adt) { - BKE_animdata_blend_write(writer, gpd->adt); - } + /* write gpd data block to file */ + BLO_write_id_struct(writer, bGPdata, id_address, &gpd->id); + BKE_id_blend_write(writer, &gpd->id); - BKE_defbase_blend_write(writer, &gpd->vertex_group_names); + if (gpd->adt) { + BKE_animdata_blend_write(writer, gpd->adt); + } - BLO_write_pointer_array(writer, gpd->totcol, gpd->mat); + BKE_defbase_blend_write(writer, &gpd->vertex_group_names); - /* write grease-pencil layers to file */ - BLO_write_struct_list(writer, bGPDlayer, &gpd->layers); - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - /* Write mask list. */ - BLO_write_struct_list(writer, bGPDlayer_Mask, &gpl->mask_layers); - /* write this layer's frames to file */ - BLO_write_struct_list(writer, bGPDframe, &gpl->frames); - LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - /* write strokes */ - BLO_write_struct_list(writer, bGPDstroke, &gpf->strokes); - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points); - BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles); - BKE_defvert_blend_write(writer, gps->totpoints, gps->dvert); - if (gps->editcurve != NULL) { - bGPDcurve *gpc = gps->editcurve; - BLO_write_struct(writer, bGPDcurve, gpc); - BLO_write_struct_array( - writer, bGPDcurve_point, gpc->tot_curve_points, gpc->curve_points); - } + BLO_write_pointer_array(writer, gpd->totcol, gpd->mat); + + /* write grease-pencil layers to file */ + BLO_write_struct_list(writer, bGPDlayer, &gpd->layers); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + /* Write mask list. */ + BLO_write_struct_list(writer, bGPDlayer_Mask, &gpl->mask_layers); + /* write this layer's frames to file */ + BLO_write_struct_list(writer, bGPDframe, &gpl->frames); + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + /* write strokes */ + BLO_write_struct_list(writer, bGPDstroke, &gpf->strokes); + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points); + BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles); + BKE_defvert_blend_write(writer, gps->totpoints, gps->dvert); + if (gps->editcurve != NULL) { + bGPDcurve *gpc = gps->editcurve; + BLO_write_struct(writer, bGPDcurve, gpc); + BLO_write_struct_array( + writer, bGPDcurve_point, gpc->tot_curve_points, gpc->curve_points); } } } diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 2894d6daf23..af7cc0acb57 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -114,32 +114,31 @@ static void hair_foreach_id(ID *id, LibraryForeachIDData *data) static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Hair *hair = (Hair *)id; - if (hair->id.us > 0 || BLO_write_is_undo(writer)) { - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); - - /* Write LibData */ - BLO_write_id_struct(writer, Hair, id_address, &hair->id); - BKE_id_blend_write(writer, &hair->id); - - /* Direct data */ - CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id); - CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id); - - BLO_write_pointer_array(writer, hair->totcol, hair->mat); - if (hair->adt) { - BKE_animdata_blend_write(writer, hair->adt); - } - /* Remove temporary data. */ - if (players && players != players_buff) { - MEM_freeN(players); - } - if (clayers && clayers != clayers_buff) { - MEM_freeN(clayers); - } + CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); + + /* Write LibData */ + BLO_write_id_struct(writer, Hair, id_address, &hair->id); + BKE_id_blend_write(writer, &hair->id); + + /* Direct data */ + CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id); + CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id); + + BLO_write_pointer_array(writer, hair->totcol, hair->mat); + if (hair->adt) { + BKE_animdata_blend_write(writer, hair->adt); + } + + /* Remove temporary data. */ + if (players && players != players_buff) { + MEM_freeN(players); + } + if (clayers && clayers != clayers_buff) { + MEM_freeN(clayers); } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index d2ab54de697..de9f2a5a656 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -229,44 +229,43 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres { Image *ima = (Image *)id; const bool is_undo = BLO_write_is_undo(writer); - if (ima->id.us > 0 || is_undo) { - ImagePackedFile *imapf; - BLI_assert(ima->packedfile == NULL); - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) { - BLI_listbase_clear(&ima->packedfiles); - } - else { - /* Some trickery to keep forward compatibility of packed images. */ - if (ima->packedfiles.first != NULL) { - imapf = ima->packedfiles.first; - ima->packedfile = imapf->packedfile; - } + ImagePackedFile *imapf; + + BLI_assert(ima->packedfile == NULL); + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) { + BLI_listbase_clear(&ima->packedfiles); + } + else { + /* Some trickery to keep forward compatibility of packed images. */ + if (ima->packedfiles.first != NULL) { + imapf = ima->packedfiles.first; + ima->packedfile = imapf->packedfile; } + } - /* write LibData */ - BLO_write_id_struct(writer, Image, id_address, &ima->id); - BKE_id_blend_write(writer, &ima->id); + /* write LibData */ + BLO_write_id_struct(writer, Image, id_address, &ima->id); + BKE_id_blend_write(writer, &ima->id); - for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { - BLO_write_struct(writer, ImagePackedFile, imapf); - BKE_packedfile_blend_write(writer, imapf->packedfile); - } + for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { + BLO_write_struct(writer, ImagePackedFile, imapf); + BKE_packedfile_blend_write(writer, imapf->packedfile); + } - BKE_previewimg_blend_write(writer, ima->preview); + BKE_previewimg_blend_write(writer, ima->preview); - LISTBASE_FOREACH (ImageView *, iv, &ima->views) { - BLO_write_struct(writer, ImageView, iv); - } - BLO_write_struct(writer, Stereo3dFormat, ima->stereo3d_format); + LISTBASE_FOREACH (ImageView *, iv, &ima->views) { + BLO_write_struct(writer, ImageView, iv); + } + BLO_write_struct(writer, Stereo3dFormat, ima->stereo3d_format); - BLO_write_struct_list(writer, ImageTile, &ima->tiles); + BLO_write_struct_list(writer, ImageTile, &ima->tiles); - ima->packedfile = NULL; + ima->packedfile = NULL; - BLO_write_struct_list(writer, RenderSlot, &ima->renderslots); - } + BLO_write_struct_list(writer, RenderSlot, &ima->renderslots); } static void image_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 724216bee6c..b59f51c36f7 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -114,27 +114,26 @@ static void shapekey_blend_write(BlendWriter *writer, ID *id, const void *id_add { Key *key = (Key *)id; const bool is_undo = BLO_write_is_undo(writer); - if (key->id.us > 0 || is_undo) { - /* write LibData */ - BLO_write_id_struct(writer, Key, id_address, &key->id); - BKE_id_blend_write(writer, &key->id); - - if (key->adt) { - BKE_animdata_blend_write(writer, key->adt); - } - - /* direct data */ - LISTBASE_FOREACH (KeyBlock *, kb, &key->block) { - KeyBlock tmp_kb = *kb; - /* Do not store actual geometry data in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(key) && !is_undo) { - tmp_kb.totelem = 0; - tmp_kb.data = NULL; - } - BLO_write_struct_at_address(writer, KeyBlock, kb, &tmp_kb); - if (tmp_kb.data != NULL) { - BLO_write_raw(writer, tmp_kb.totelem * key->elemsize, tmp_kb.data); - } + + /* write LibData */ + BLO_write_id_struct(writer, Key, id_address, &key->id); + BKE_id_blend_write(writer, &key->id); + + if (key->adt) { + BKE_animdata_blend_write(writer, key->adt); + } + + /* direct data */ + LISTBASE_FOREACH (KeyBlock *, kb, &key->block) { + KeyBlock tmp_kb = *kb; + /* Do not store actual geometry data in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(key) && !is_undo) { + tmp_kb.totelem = 0; + tmp_kb.data = NULL; + } + BLO_write_struct_at_address(writer, KeyBlock, kb, &tmp_kb); + if (tmp_kb.data != NULL) { + BLO_write_raw(writer, tmp_kb.totelem * key->elemsize, tmp_kb.data); } } } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 9875d776d33..e804f32e5a6 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -137,26 +137,25 @@ static void lattice_foreach_id(ID *id, LibraryForeachIDData *data) static void lattice_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Lattice *lt = (Lattice *)id; - if (lt->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - lt->editlatt = NULL; - lt->batch_cache = NULL; - - /* write LibData */ - BLO_write_id_struct(writer, Lattice, id_address, <->id); - BKE_id_blend_write(writer, <->id); - - /* write animdata */ - if (lt->adt) { - BKE_animdata_blend_write(writer, lt->adt); - } - /* direct data */ - BLO_write_struct_array(writer, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + lt->editlatt = NULL; + lt->batch_cache = NULL; + + /* write LibData */ + BLO_write_id_struct(writer, Lattice, id_address, <->id); + BKE_id_blend_write(writer, <->id); - BKE_defbase_blend_write(writer, <->vertex_group_names); - BKE_defvert_blend_write(writer, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); + /* write animdata */ + if (lt->adt) { + BKE_animdata_blend_write(writer, lt->adt); } + + /* direct data */ + BLO_write_struct_array(writer, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + + BKE_defbase_blend_write(writer, <->vertex_group_names); + BKE_defvert_blend_write(writer, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); } static void lattice_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index d91d80ac683..c2b71b85973 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -136,27 +136,26 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data) static void light_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Light *la = (Light *)id; - if (la->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, Light, id_address, &la->id); - BKE_id_blend_write(writer, &la->id); - if (la->adt) { - BKE_animdata_blend_write(writer, la->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Light, id_address, &la->id); + BKE_id_blend_write(writer, &la->id); - if (la->curfalloff) { - BKE_curvemapping_blend_write(writer, la->curfalloff); - } + if (la->adt) { + BKE_animdata_blend_write(writer, la->adt); + } - /* Node-tree is integral part of lights, no libdata. */ - if (la->nodetree) { - BLO_write_struct(writer, bNodeTree, la->nodetree); - ntreeBlendWrite(writer, la->nodetree); - } + if (la->curfalloff) { + BKE_curvemapping_blend_write(writer, la->curfalloff); + } - BKE_previewimg_blend_write(writer, la->preview); + /* Node-tree is integral part of lights, no libdata. */ + if (la->nodetree) { + BLO_write_struct(writer, bNodeTree, la->nodetree); + ntreeBlendWrite(writer, la->nodetree); } + + BKE_previewimg_blend_write(writer, la->preview); } static void light_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index b09aed82921..15733af8ef0 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -60,14 +60,13 @@ static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data) static void lightprobe_blend_write(BlendWriter *writer, ID *id, const void *id_address) { LightProbe *prb = (LightProbe *)id; - if (prb->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, LightProbe, id_address, &prb->id); - BKE_id_blend_write(writer, &prb->id); - - if (prb->adt) { - BKE_animdata_blend_write(writer, prb->adt); - } + + /* write LibData */ + BLO_write_id_struct(writer, LightProbe, id_address, &prb->id); + BKE_id_blend_write(writer, &prb->id); + + if (prb->adt) { + BKE_animdata_blend_write(writer, prb->adt); } } diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 26d9ab7a8c7..19030fca38b 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -457,28 +457,27 @@ static void write_linestyle_geometry_modifiers(BlendWriter *writer, ListBase *mo static void linestyle_blend_write(BlendWriter *writer, ID *id, const void *id_address) { FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; - if (linestyle->id.us > 0 || BLO_write_is_undo(writer)) { - BLO_write_id_struct(writer, FreestyleLineStyle, id_address, &linestyle->id); - BKE_id_blend_write(writer, &linestyle->id); - if (linestyle->adt) { - BKE_animdata_blend_write(writer, linestyle->adt); - } + BLO_write_id_struct(writer, FreestyleLineStyle, id_address, &linestyle->id); + BKE_id_blend_write(writer, &linestyle->id); - write_linestyle_color_modifiers(writer, &linestyle->color_modifiers); - write_linestyle_alpha_modifiers(writer, &linestyle->alpha_modifiers); - write_linestyle_thickness_modifiers(writer, &linestyle->thickness_modifiers); - write_linestyle_geometry_modifiers(writer, &linestyle->geometry_modifiers); - for (int a = 0; a < MAX_MTEX; a++) { - if (linestyle->mtex[a]) { - BLO_write_struct(writer, MTex, linestyle->mtex[a]); - } - } - if (linestyle->nodetree) { - BLO_write_struct(writer, bNodeTree, linestyle->nodetree); - ntreeBlendWrite(writer, linestyle->nodetree); + if (linestyle->adt) { + BKE_animdata_blend_write(writer, linestyle->adt); + } + + write_linestyle_color_modifiers(writer, &linestyle->color_modifiers); + write_linestyle_alpha_modifiers(writer, &linestyle->alpha_modifiers); + write_linestyle_thickness_modifiers(writer, &linestyle->thickness_modifiers); + write_linestyle_geometry_modifiers(writer, &linestyle->geometry_modifiers); + for (int a = 0; a < MAX_MTEX; a++) { + if (linestyle->mtex[a]) { + BLO_write_struct(writer, MTex, linestyle->mtex[a]); } } + if (linestyle->nodetree) { + BLO_write_struct(writer, bNodeTree, linestyle->nodetree); + ntreeBlendWrite(writer, linestyle->nodetree); + } } static void direct_link_linestyle_color_modifier(BlendDataReader *reader, diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index f40d1db60ff..a93fcb6e8e0 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -101,48 +101,47 @@ static void mask_foreach_id(ID *id, LibraryForeachIDData *data) static void mask_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Mask *mask = (Mask *)id; - if (mask->id.us > 0 || BLO_write_is_undo(writer)) { - MaskLayer *masklay; - BLO_write_id_struct(writer, Mask, id_address, &mask->id); - BKE_id_blend_write(writer, &mask->id); + MaskLayer *masklay; - if (mask->adt) { - BKE_animdata_blend_write(writer, mask->adt); - } + BLO_write_id_struct(writer, Mask, id_address, &mask->id); + BKE_id_blend_write(writer, &mask->id); - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - MaskSpline *spline; - MaskLayerShape *masklay_shape; + if (mask->adt) { + BKE_animdata_blend_write(writer, mask->adt); + } - BLO_write_struct(writer, MaskLayer, masklay); + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + MaskLayerShape *masklay_shape; - for (spline = masklay->splines.first; spline; spline = spline->next) { - int i; + BLO_write_struct(writer, MaskLayer, masklay); - void *points_deform = spline->points_deform; - spline->points_deform = NULL; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; - BLO_write_struct(writer, MaskSpline, spline); - BLO_write_struct_array(writer, MaskSplinePoint, spline->tot_point, spline->points); + void *points_deform = spline->points_deform; + spline->points_deform = NULL; - spline->points_deform = points_deform; + BLO_write_struct(writer, MaskSpline, spline); + BLO_write_struct_array(writer, MaskSplinePoint, spline->tot_point, spline->points); - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point = &spline->points[i]; + spline->points_deform = points_deform; - if (point->tot_uw) { - BLO_write_struct_array(writer, MaskSplinePointUW, point->tot_uw, point->uw); - } + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + + if (point->tot_uw) { + BLO_write_struct_array(writer, MaskSplinePointUW, point->tot_uw, point->uw); } } + } - for (masklay_shape = masklay->splines_shapes.first; masklay_shape; - masklay_shape = masklay_shape->next) { - BLO_write_struct(writer, MaskLayerShape, masklay_shape); - BLO_write_float_array( - writer, masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data); - } + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + BLO_write_struct(writer, MaskLayerShape, masklay_shape); + BLO_write_float_array( + writer, masklay_shape->tot_vert * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data); } } } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index ca57038f1c4..13b5bca5638 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -179,31 +179,30 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data) static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Material *ma = (Material *)id; - if (ma->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - ma->texpaintslot = NULL; - BLI_listbase_clear(&ma->gpumaterial); - /* write LibData */ - BLO_write_id_struct(writer, Material, id_address, &ma->id); - BKE_id_blend_write(writer, &ma->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + ma->texpaintslot = NULL; + BLI_listbase_clear(&ma->gpumaterial); - if (ma->adt) { - BKE_animdata_blend_write(writer, ma->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Material, id_address, &ma->id); + BKE_id_blend_write(writer, &ma->id); - /* nodetree is integral part of material, no libdata */ - if (ma->nodetree) { - BLO_write_struct(writer, bNodeTree, ma->nodetree); - ntreeBlendWrite(writer, ma->nodetree); - } + if (ma->adt) { + BKE_animdata_blend_write(writer, ma->adt); + } - BKE_previewimg_blend_write(writer, ma->preview); + /* nodetree is integral part of material, no libdata */ + if (ma->nodetree) { + BLO_write_struct(writer, bNodeTree, ma->nodetree); + ntreeBlendWrite(writer, ma->nodetree); + } - /* grease pencil settings */ - if (ma->gp_style) { - BLO_write_struct(writer, MaterialGPencilStyle, ma->gp_style); - } + BKE_previewimg_blend_write(writer, ma->preview); + + /* grease pencil settings */ + if (ma->gp_style) { + BLO_write_struct(writer, MaterialGPencilStyle, ma->gp_style); } } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index d6b189d484b..45cf0f17840 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -119,28 +119,27 @@ static void metaball_foreach_id(ID *id, LibraryForeachIDData *data) static void metaball_blend_write(BlendWriter *writer, ID *id, const void *id_address) { MetaBall *mb = (MetaBall *)id; - if (mb->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - BLI_listbase_clear(&mb->disp); - mb->editelems = NULL; - /* Must always be cleared (meta's don't have their own edit-data). */ - mb->needs_flush_to_id = 0; - mb->lastelem = NULL; - mb->batch_cache = NULL; - - /* write LibData */ - BLO_write_id_struct(writer, MetaBall, id_address, &mb->id); - BKE_id_blend_write(writer, &mb->id); - - /* direct data */ - BLO_write_pointer_array(writer, mb->totcol, mb->mat); - if (mb->adt) { - BKE_animdata_blend_write(writer, mb->adt); - } - LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { - BLO_write_struct(writer, MetaElem, ml); - } + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + BLI_listbase_clear(&mb->disp); + mb->editelems = NULL; + /* Must always be cleared (meta's don't have their own edit-data). */ + mb->needs_flush_to_id = 0; + mb->lastelem = NULL; + mb->batch_cache = NULL; + + /* write LibData */ + BLO_write_id_struct(writer, MetaBall, id_address, &mb->id); + BKE_id_blend_write(writer, &mb->id); + + /* direct data */ + BLO_write_pointer_array(writer, mb->totcol, mb->mat); + if (mb->adt) { + BKE_animdata_blend_write(writer, mb->adt); + } + + LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { + BLO_write_struct(writer, MetaElem, ml); } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index e99670fc488..8257e54c618 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -179,95 +179,90 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address { Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); - if (mesh->id.us > 0 || is_undo) { - CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - - /* cache only - don't write */ - mesh->mface = NULL; - mesh->totface = 0; - memset(&mesh->fdata, 0, sizeof(mesh->fdata)); - memset(&mesh->runtime, 0, sizeof(mesh->runtime)); - flayers = flayers_buff; - - /* Do not store actual geometry data in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { - mesh->mvert = NULL; - mesh->totvert = 0; - memset(&mesh->vdata, 0, sizeof(mesh->vdata)); - vlayers = vlayers_buff; - - mesh->medge = NULL; - mesh->totedge = 0; - memset(&mesh->edata, 0, sizeof(mesh->edata)); - elayers = elayers_buff; - - mesh->mloop = NULL; - mesh->totloop = 0; - memset(&mesh->ldata, 0, sizeof(mesh->ldata)); - llayers = llayers_buff; - - mesh->mpoly = NULL; - mesh->totpoly = 0; - memset(&mesh->pdata, 0, sizeof(mesh->pdata)); - players = players_buff; - } - else { - CustomData_blend_write_prepare( - &mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); - CustomData_blend_write_prepare( - &mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); - CustomData_blend_write_prepare( - &mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); - CustomData_blend_write_prepare( - &mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - } - BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); - BKE_id_blend_write(writer, &mesh->id); + CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - /* direct data */ - if (mesh->adt) { - BKE_animdata_blend_write(writer, mesh->adt); - } + /* cache only - don't write */ + mesh->mface = NULL; + mesh->totface = 0; + memset(&mesh->fdata, 0, sizeof(mesh->fdata)); + memset(&mesh->runtime, 0, sizeof(mesh->runtime)); + flayers = flayers_buff; + + /* Do not store actual geometry data in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { + mesh->mvert = NULL; + mesh->totvert = 0; + memset(&mesh->vdata, 0, sizeof(mesh->vdata)); + vlayers = vlayers_buff; + + mesh->medge = NULL; + mesh->totedge = 0; + memset(&mesh->edata, 0, sizeof(mesh->edata)); + elayers = elayers_buff; + + mesh->mloop = NULL; + mesh->totloop = 0; + memset(&mesh->ldata, 0, sizeof(mesh->ldata)); + llayers = llayers_buff; + + mesh->mpoly = NULL; + mesh->totpoly = 0; + memset(&mesh->pdata, 0, sizeof(mesh->pdata)); + players = players_buff; + } + else { + CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); + CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); + CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); + CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + } + + BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); + BKE_id_blend_write(writer, &mesh->id); - BKE_defbase_blend_write(writer, &mesh->vertex_group_names); + /* direct data */ + if (mesh->adt) { + BKE_animdata_blend_write(writer, mesh->adt); + } + + BKE_defbase_blend_write(writer, &mesh->vertex_group_names); - BLO_write_pointer_array(writer, mesh->totcol, mesh->mat); - BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect); + BLO_write_pointer_array(writer, mesh->totcol, mesh->mat); + BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect); - CustomData_blend_write( - writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id); - CustomData_blend_write( - writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id); - /* fdata is really a dummy - written so slots align */ - CustomData_blend_write( - writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id); - CustomData_blend_write( - writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id); - CustomData_blend_write( - writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id); + CustomData_blend_write( + writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id); + CustomData_blend_write( + writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id); + /* fdata is really a dummy - written so slots align */ + CustomData_blend_write( + writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id); + CustomData_blend_write( + writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id); + CustomData_blend_write( + writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id); - /* Free temporary data */ + /* Free temporary data */ -/* Free custom-data layers, when not assigned a buffer value. */ + /* Free custom-data layers, when not assigned a buffer value. */ #define CD_LAYERS_FREE(id) \ if (id && id != id##_buff) { \ MEM_freeN(id); \ } \ ((void)0) - CD_LAYERS_FREE(vlayers); - CD_LAYERS_FREE(elayers); - // CD_LAYER_FREE(flayers); /* Never allocated. */ - CD_LAYERS_FREE(llayers); - CD_LAYERS_FREE(players); + CD_LAYERS_FREE(vlayers); + CD_LAYERS_FREE(elayers); + // CD_LAYER_FREE(flayers); /* Never allocated. */ + CD_LAYERS_FREE(llayers); + CD_LAYERS_FREE(players); #undef CD_LAYERS_FREE - } } static void mesh_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index f32b0c434c1..e507252307b 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -206,36 +206,35 @@ static void write_movieReconstruction(BlendWriter *writer, static void movieclip_blend_write(BlendWriter *writer, ID *id, const void *id_address) { MovieClip *clip = (MovieClip *)id; - if (clip->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - clip->anim = NULL; - clip->tracking_context = NULL; - clip->tracking.stats = NULL; - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + clip->anim = NULL; + clip->tracking_context = NULL; + clip->tracking.stats = NULL; - BLO_write_id_struct(writer, MovieClip, id_address, &clip->id); - BKE_id_blend_write(writer, &clip->id); + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; - if (clip->adt) { - BKE_animdata_blend_write(writer, clip->adt); - } + BLO_write_id_struct(writer, MovieClip, id_address, &clip->id); + BKE_id_blend_write(writer, &clip->id); + + if (clip->adt) { + BKE_animdata_blend_write(writer, clip->adt); + } - write_movieTracks(writer, &tracking->tracks); - write_moviePlaneTracks(writer, &tracking->plane_tracks); - write_movieReconstruction(writer, &tracking->reconstruction); + write_movieTracks(writer, &tracking->tracks); + write_moviePlaneTracks(writer, &tracking->plane_tracks); + write_movieReconstruction(writer, &tracking->reconstruction); - object = tracking->objects.first; - while (object) { - BLO_write_struct(writer, MovieTrackingObject, object); + object = tracking->objects.first; + while (object) { + BLO_write_struct(writer, MovieTrackingObject, object); - write_movieTracks(writer, &object->tracks); - write_moviePlaneTracks(writer, &object->plane_tracks); - write_movieReconstruction(writer, &object->reconstruction); + write_movieTracks(writer, &object->tracks); + write_moviePlaneTracks(writer, &object->plane_tracks); + write_movieReconstruction(writer, &object->reconstruction); - object = object->next; - } + object = object->next; } } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index bd22f049a8b..2a0e05a2616 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -606,19 +606,18 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bNodeTree *ntree = (bNodeTree *)id; - if (ntree->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - ntree->init = 0; /* to set callbacks and force setting types */ - ntree->is_updating = false; - ntree->typeinfo = nullptr; - ntree->interface_type = nullptr; - ntree->progress = nullptr; - ntree->execdata = nullptr; - BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + ntree->init = 0; /* to set callbacks and force setting types */ + ntree->is_updating = false; + ntree->typeinfo = nullptr; + ntree->interface_type = nullptr; + ntree->progress = nullptr; + ntree->execdata = nullptr; - ntreeBlendWrite(writer, ntree); - } + BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); + + ntreeBlendWrite(writer, ntree); } static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 86db4b6ace8..1c08a46adc3 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -523,74 +523,72 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre Object *ob = (Object *)id; const bool is_undo = BLO_write_is_undo(writer); - if (ob->id.us > 0 || is_undo) { - /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ - BKE_object_runtime_reset(ob); - if (is_undo) { - /* For undo we stay in object mode during undo presses, so keep edit-mode disabled on save as - * well, can help reducing false detection of changed data-blocks. */ - ob->mode &= ~OB_MODE_EDIT; - } + /* Clean up, important in undo case to reduce false detection of changed data-blocks. */ + BKE_object_runtime_reset(ob); + + if (is_undo) { + /* For undo we stay in object mode during undo presses, so keep edit-mode disabled on save as + * well, can help reducing false detection of changed data-blocks. */ + ob->mode &= ~OB_MODE_EDIT; + } - /* write LibData */ - BLO_write_id_struct(writer, Object, id_address, &ob->id); - BKE_id_blend_write(writer, &ob->id); + /* write LibData */ + BLO_write_id_struct(writer, Object, id_address, &ob->id); + BKE_id_blend_write(writer, &ob->id); - if (ob->adt) { - BKE_animdata_blend_write(writer, ob->adt); - } + if (ob->adt) { + BKE_animdata_blend_write(writer, ob->adt); + } - /* direct data */ - BLO_write_pointer_array(writer, ob->totcol, ob->mat); - BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits); + /* direct data */ + BLO_write_pointer_array(writer, ob->totcol, ob->mat); + BLO_write_raw(writer, sizeof(char) * ob->totcol, ob->matbits); - bArmature *arm = NULL; - if (ob->type == OB_ARMATURE) { - arm = ob->data; - if (arm && ob->pose && arm->act_bone) { - BLI_strncpy( - ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone)); - } + bArmature *arm = NULL; + if (ob->type == OB_ARMATURE) { + arm = ob->data; + if (arm && ob->pose && arm->act_bone) { + BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone)); } + } - BKE_pose_blend_write(writer, ob->pose, arm); - write_fmaps(writer, &ob->fmaps); - BKE_constraint_blend_write(writer, &ob->constraints); - animviz_motionpath_blend_write(writer, ob->mpath); + BKE_pose_blend_write(writer, ob->pose, arm); + write_fmaps(writer, &ob->fmaps); + BKE_constraint_blend_write(writer, &ob->constraints); + animviz_motionpath_blend_write(writer, ob->mpath); - BLO_write_struct(writer, PartDeflect, ob->pd); - if (ob->soft) { - /* Set deprecated pointers to prevent crashes of older Blenders */ - ob->soft->pointcache = ob->soft->shared->pointcache; - ob->soft->ptcaches = ob->soft->shared->ptcaches; - BLO_write_struct(writer, SoftBody, ob->soft); - BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared); - BKE_ptcache_blend_write(writer, &(ob->soft->shared->ptcaches)); - BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights); - } + BLO_write_struct(writer, PartDeflect, ob->pd); + if (ob->soft) { + /* Set deprecated pointers to prevent crashes of older Blenders */ + ob->soft->pointcache = ob->soft->shared->pointcache; + ob->soft->ptcaches = ob->soft->shared->ptcaches; + BLO_write_struct(writer, SoftBody, ob->soft); + BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared); + BKE_ptcache_blend_write(writer, &(ob->soft->shared->ptcaches)); + BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights); + } - if (ob->rigidbody_object) { - /* TODO: if any extra data is added to handle duplis, will need separate function then */ - BLO_write_struct(writer, RigidBodyOb, ob->rigidbody_object); - } - if (ob->rigidbody_constraint) { - BLO_write_struct(writer, RigidBodyCon, ob->rigidbody_constraint); - } + if (ob->rigidbody_object) { + /* TODO: if any extra data is added to handle duplis, will need separate function then */ + BLO_write_struct(writer, RigidBodyOb, ob->rigidbody_object); + } + if (ob->rigidbody_constraint) { + BLO_write_struct(writer, RigidBodyCon, ob->rigidbody_constraint); + } - if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { - BLO_write_struct(writer, ImageUser, ob->iuser); - } + if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { + BLO_write_struct(writer, ImageUser, ob->iuser); + } - BKE_particle_system_blend_write(writer, &ob->particlesystem); - BKE_modifier_blend_write(writer, &ob->modifiers); - BKE_gpencil_modifier_blend_write(writer, &ob->greasepencil_modifiers); - BKE_shaderfx_blend_write(writer, &ob->shader_fx); + BKE_particle_system_blend_write(writer, &ob->particlesystem); + BKE_modifier_blend_write(writer, &ob->modifiers); + BKE_gpencil_modifier_blend_write(writer, &ob->greasepencil_modifiers); + BKE_shaderfx_blend_write(writer, &ob->shader_fx); - BLO_write_struct_list(writer, LinkData, &ob->pc_ids); + BLO_write_struct_list(writer, LinkData, &ob->pc_ids); - BKE_previewimg_blend_write(writer, ob->preview); - } + BKE_previewimg_blend_write(writer, ob->preview); } /* XXX deprecated - old animation system */ diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index a1fa6aae1ce..d6030941c6d 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -108,14 +108,13 @@ static void palette_free_data(ID *id) static void palette_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Palette *palette = (Palette *)id; - if (palette->id.us > 0 || BLO_write_is_undo(writer)) { - PaletteColor *color; - BLO_write_id_struct(writer, Palette, id_address, &palette->id); - BKE_id_blend_write(writer, &palette->id); - for (color = palette->colors.first; color; color = color->next) { - BLO_write_struct(writer, PaletteColor, color); - } + PaletteColor *color; + BLO_write_id_struct(writer, Palette, id_address, &palette->id); + BKE_id_blend_write(writer, &palette->id); + + for (color = palette->colors.first; color; color = color->next) { + BLO_write_struct(writer, PaletteColor, color); } } @@ -187,12 +186,11 @@ static void paint_curve_free_data(ID *id) static void paint_curve_blend_write(BlendWriter *writer, ID *id, const void *id_address) { PaintCurve *pc = (PaintCurve *)id; - if (pc->id.us > 0 || BLO_write_is_undo(writer)) { - BLO_write_id_struct(writer, PaintCurve, id_address, &pc->id); - BKE_id_blend_write(writer, &pc->id); - BLO_write_struct_array(writer, PaintCurvePoint, pc->tot_points, pc->points); - } + BLO_write_id_struct(writer, PaintCurve, id_address, &pc->id); + BKE_id_blend_write(writer, &pc->id); + + BLO_write_struct_array(writer, PaintCurvePoint, pc->tot_points, pc->points); } static void paint_curve_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index cc8a051eceb..29849c69b6f 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -255,60 +255,59 @@ static void write_boid_state(BlendWriter *writer, BoidState *state) static void particle_settings_blend_write(BlendWriter *writer, ID *id, const void *id_address) { ParticleSettings *part = (ParticleSettings *)id; - if (part->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id); - BKE_id_blend_write(writer, &part->id); - if (part->adt) { - BKE_animdata_blend_write(writer, part->adt); - } - BLO_write_struct(writer, PartDeflect, part->pd); - BLO_write_struct(writer, PartDeflect, part->pd2); - BLO_write_struct(writer, EffectorWeights, part->effector_weights); + /* write LibData */ + BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id); + BKE_id_blend_write(writer, &part->id); - if (part->clumpcurve) { - BKE_curvemapping_blend_write(writer, part->clumpcurve); - } - if (part->roughcurve) { - BKE_curvemapping_blend_write(writer, part->roughcurve); - } - if (part->twistcurve) { - BKE_curvemapping_blend_write(writer, part->twistcurve); - } + if (part->adt) { + BKE_animdata_blend_write(writer, part->adt); + } + BLO_write_struct(writer, PartDeflect, part->pd); + BLO_write_struct(writer, PartDeflect, part->pd2); + BLO_write_struct(writer, EffectorWeights, part->effector_weights); - LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { - /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */ - if (dw->ob != NULL) { - dw->index = 0; - if (part->instance_collection) { /* can be NULL if lining fails or set to None */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) { - if (object == dw->ob) { - break; - } - dw->index++; + if (part->clumpcurve) { + BKE_curvemapping_blend_write(writer, part->clumpcurve); + } + if (part->roughcurve) { + BKE_curvemapping_blend_write(writer, part->roughcurve); + } + if (part->twistcurve) { + BKE_curvemapping_blend_write(writer, part->twistcurve); + } + + LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) { + /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */ + if (dw->ob != NULL) { + dw->index = 0; + if (part->instance_collection) { /* can be NULL if lining fails or set to None */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) { + if (object == dw->ob) { + break; } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + dw->index++; } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } - BLO_write_struct(writer, ParticleDupliWeight, dw); } + BLO_write_struct(writer, ParticleDupliWeight, dw); + } - if (part->boids && part->phystype == PART_PHYS_BOIDS) { - BLO_write_struct(writer, BoidSettings, part->boids); + if (part->boids && part->phystype == PART_PHYS_BOIDS) { + BLO_write_struct(writer, BoidSettings, part->boids); - LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { - write_boid_state(writer, state); - } - } - if (part->fluid && part->phystype == PART_PHYS_FLUID) { - BLO_write_struct(writer, SPHFluidSettings, part->fluid); + LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { + write_boid_state(writer, state); } + } + if (part->fluid && part->phystype == PART_PHYS_FLUID) { + BLO_write_struct(writer, SPHFluidSettings, part->fluid); + } - for (int a = 0; a < MAX_MTEX; a++) { - if (part->mtex[a]) { - BLO_write_struct(writer, MTex, part->mtex[a]); - } + for (int a = 0; a < MAX_MTEX; a++) { + if (part->mtex[a]) { + BLO_write_struct(writer, MTex, part->mtex[a]); } } } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index d9a7a376e2e..837a772607f 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -112,28 +112,27 @@ static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data) static void pointcloud_blend_write(BlendWriter *writer, ID *id, const void *id_address) { PointCloud *pointcloud = (PointCloud *)id; - if (pointcloud->id.us > 0 || BLO_write_is_undo(writer)) { - CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; - CustomData_blend_write_prepare( - &pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - - /* Write LibData */ - BLO_write_id_struct(writer, PointCloud, id_address, &pointcloud->id); - BKE_id_blend_write(writer, &pointcloud->id); - - /* Direct data */ - CustomData_blend_write( - writer, &pointcloud->pdata, players, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id); - - BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat); - if (pointcloud->adt) { - BKE_animdata_blend_write(writer, pointcloud->adt); - } - /* Remove temporary data. */ - if (players && players != players_buff) { - MEM_freeN(players); - } + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomData_blend_write_prepare( + &pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + + /* Write LibData */ + BLO_write_id_struct(writer, PointCloud, id_address, &pointcloud->id); + BKE_id_blend_write(writer, &pointcloud->id); + + /* Direct data */ + CustomData_blend_write( + writer, &pointcloud->pdata, players, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id); + + BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat); + if (pointcloud->adt) { + BKE_animdata_blend_write(writer, pointcloud->adt); + } + + /* Remove temporary data. */ + if (players && players != players_buff) { + MEM_freeN(players); } } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index e44c5a6b40e..1e725a6afc4 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -255,18 +255,16 @@ static void screen_foreach_id(ID *id, LibraryForeachIDData *data) static void screen_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bScreen *screen = (bScreen *)id; - /* Screens are reference counted, only saved if used by a workspace. */ - if (screen->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ - BLO_write_struct_at_address_with_filecode(writer, ID_SCRN, bScreen, id_address, screen); - BKE_id_blend_write(writer, &screen->id); - BKE_previewimg_blend_write(writer, screen->preview); + /* write LibData */ + /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ + BLO_write_struct_at_address_with_filecode(writer, ID_SCRN, bScreen, id_address, screen); + BKE_id_blend_write(writer, &screen->id); - /* direct data */ - BKE_screen_area_map_blend_write(writer, AREAMAP_FROM_SCREEN(screen)); - } + BKE_previewimg_blend_write(writer, screen->preview); + + /* direct data */ + BKE_screen_area_map_blend_write(writer, AREAMAP_FROM_SCREEN(screen)); } /* Cannot use IDTypeInfo callback yet, because of the return value. */ diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 216563b860d..5aac29c19a7 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -114,19 +114,18 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) static void simulation_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Simulation *simulation = (Simulation *)id; - if (simulation->id.us > 0 || BLO_write_is_undo(writer)) { - BLO_write_id_struct(writer, Simulation, id_address, &simulation->id); - BKE_id_blend_write(writer, &simulation->id); - - if (simulation->adt) { - BKE_animdata_blend_write(writer, simulation->adt); - } - - /* nodetree is integral part of simulation, no libdata */ - if (simulation->nodetree) { - BLO_write_struct(writer, bNodeTree, simulation->nodetree); - ntreeBlendWrite(writer, simulation->nodetree); - } + + BLO_write_id_struct(writer, Simulation, id_address, &simulation->id); + BKE_id_blend_write(writer, &simulation->id); + + if (simulation->adt) { + BKE_animdata_blend_write(writer, simulation->adt); + } + + /* nodetree is integral part of simulation, no libdata */ + if (simulation->nodetree) { + BLO_write_struct(writer, bNodeTree, simulation->nodetree); + ntreeBlendWrite(writer, simulation->nodetree); } } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 8730d2758e6..c61fa793367 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -137,24 +137,23 @@ static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_addres { bSound *sound = (bSound *)id; const bool is_undo = BLO_write_is_undo(writer); - if (sound->id.us > 0 || is_undo) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - sound->tags = 0; - sound->handle = NULL; - sound->playback_handle = NULL; - sound->spinlock = NULL; - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(sound) && !is_undo) { - sound->packedfile = NULL; - } - - /* write LibData */ - BLO_write_id_struct(writer, bSound, id_address, &sound->id); - BKE_id_blend_write(writer, &sound->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + sound->tags = 0; + sound->handle = NULL; + sound->playback_handle = NULL; + sound->spinlock = NULL; - BKE_packedfile_blend_write(writer, sound->packedfile); + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(sound) && !is_undo) { + sound->packedfile = NULL; } + + /* write LibData */ + BLO_write_id_struct(writer, bSound, id_address, &sound->id); + BKE_id_blend_write(writer, &sound->id); + + BKE_packedfile_blend_write(writer, sound->packedfile); } static void sound_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index af9b2268879..4b10522c375 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -56,14 +56,13 @@ static void speaker_foreach_id(ID *id, LibraryForeachIDData *data) static void speaker_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Speaker *spk = (Speaker *)id; - if (spk->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, Speaker, id_address, &spk->id); - BKE_id_blend_write(writer, &spk->id); - - if (spk->adt) { - BKE_animdata_blend_write(writer, spk->adt); - } + + /* write LibData */ + BLO_write_id_struct(writer, Speaker, id_address, &spk->id); + BKE_id_blend_write(writer, &spk->id); + + if (spk->adt) { + BKE_animdata_blend_write(writer, spk->adt); } } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 6048e823abb..275cf0d4c38 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -171,9 +171,6 @@ static void text_free_data(ID *id) static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address) { - if (id->us < 1 && !BLO_write_is_undo(writer)) { - return; - } Text *text = (Text *)id; /* NOTE: we are clearing local temp data here, *not* the flag in the actual 'real' ID. */ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index beb92495d16..228e6fffdf7 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -150,28 +150,27 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data) static void texture_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Tex *tex = (Tex *)id; - if (tex->id.us > 0 || BLO_write_is_undo(writer)) { - /* write LibData */ - BLO_write_id_struct(writer, Tex, id_address, &tex->id); - BKE_id_blend_write(writer, &tex->id); - if (tex->adt) { - BKE_animdata_blend_write(writer, tex->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Tex, id_address, &tex->id); + BKE_id_blend_write(writer, &tex->id); - /* direct data */ - if (tex->coba) { - BLO_write_struct(writer, ColorBand, tex->coba); - } + if (tex->adt) { + BKE_animdata_blend_write(writer, tex->adt); + } - /* nodetree is integral part of texture, no libdata */ - if (tex->nodetree) { - BLO_write_struct(writer, bNodeTree, tex->nodetree); - ntreeBlendWrite(writer, tex->nodetree); - } + /* direct data */ + if (tex->coba) { + BLO_write_struct(writer, ColorBand, tex->coba); + } - BKE_previewimg_blend_write(writer, tex->preview); + /* nodetree is integral part of texture, no libdata */ + if (tex->nodetree) { + BLO_write_struct(writer, bNodeTree, tex->nodetree); + ntreeBlendWrite(writer, tex->nodetree); } + + BKE_previewimg_blend_write(writer, tex->preview); } static void texture_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index b28d17df814..69452d6896f 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -578,27 +578,26 @@ static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_addre { Volume *volume = (Volume *)id; const bool is_undo = BLO_write_is_undo(writer); - if (volume->id.us > 0 || is_undo) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - volume->runtime.grids = nullptr; - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(volume) && !is_undo) { - volume->packedfile = nullptr; - } + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + volume->runtime.grids = nullptr; - /* write LibData */ - BLO_write_id_struct(writer, Volume, id_address, &volume->id); - BKE_id_blend_write(writer, &volume->id); + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(volume) && !is_undo) { + volume->packedfile = nullptr; + } - /* direct data */ - BLO_write_pointer_array(writer, volume->totcol, volume->mat); - if (volume->adt) { - BKE_animdata_blend_write(writer, volume->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, Volume, id_address, &volume->id); + BKE_id_blend_write(writer, &volume->id); - BKE_packedfile_blend_write(writer, volume->packedfile); + /* direct data */ + BLO_write_pointer_array(writer, volume->totcol, volume->mat); + if (volume->adt) { + BKE_animdata_blend_write(writer, volume->adt); } + + BKE_packedfile_blend_write(writer, volume->packedfile); } static void volume_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index e889d8af1d5..4abe1ff0f20 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -138,26 +138,25 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data) static void world_blend_write(BlendWriter *writer, ID *id, const void *id_address) { World *wrld = (World *)id; - if (wrld->id.us > 0 || BLO_write_is_undo(writer)) { - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - BLI_listbase_clear(&wrld->gpumaterial); - /* write LibData */ - BLO_write_id_struct(writer, World, id_address, &wrld->id); - BKE_id_blend_write(writer, &wrld->id); + /* Clean up, important in undo case to reduce false detection of changed datablocks. */ + BLI_listbase_clear(&wrld->gpumaterial); - if (wrld->adt) { - BKE_animdata_blend_write(writer, wrld->adt); - } + /* write LibData */ + BLO_write_id_struct(writer, World, id_address, &wrld->id); + BKE_id_blend_write(writer, &wrld->id); - /* nodetree is integral part of world, no libdata */ - if (wrld->nodetree) { - BLO_write_struct(writer, bNodeTree, wrld->nodetree); - ntreeBlendWrite(writer, wrld->nodetree); - } + if (wrld->adt) { + BKE_animdata_blend_write(writer, wrld->adt); + } - BKE_previewimg_blend_write(writer, wrld->preview); + /* nodetree is integral part of world, no libdata */ + if (wrld->nodetree) { + BLO_write_struct(writer, bNodeTree, wrld->nodetree); + ntreeBlendWrite(writer, wrld->nodetree); } + + BKE_previewimg_blend_write(writer, wrld->preview); } static void world_blend_read_data(BlendDataReader *reader, ID *id) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 225548f3832..337279ae84b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -982,6 +982,14 @@ static bool write_file_handle(Main *mainvar, BLI_assert( (id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0); + /* We only write unused IDs in undo case. + * NOTE: All Scenes, WindowManagers and WorkSpaces should always be written to disk, so + * their usercount should never be NULL currently. */ + if (id->us == 0 && !wd->use_memfile) { + BLI_assert(!ELEM(GS(id->name), ID_SCE, ID_WM, ID_WS)); + continue; + } + const bool do_override = !ELEM(override_storage, NULL, bmain) && ID_IS_OVERRIDE_LIBRARY_REAL(id); -- cgit v1.2.3 From e648e388874a317f7846efe9ba7242a5b11a5650 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Aug 2021 15:08:13 +0200 Subject: Undo: Clear more ID runtime data on filewrite. This should help reducing false 'changed' status detection when reading back a memfile undo step. Related to T90593 & D12242. --- source/blender/blenloader/intern/writefile.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 337279ae84b..99246603e9a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1023,12 +1023,23 @@ static bool write_file_handle(Main *mainvar, memcpy(id_buffer, id, idtype_struct_size); + /* Clear runtime data to reduce false detection of changed data in undo/redo context. */ ((ID *)id_buffer)->tag = 0; + ((ID *)id_buffer)->us = 0; + ((ID *)id_buffer)->icon_id = 0; /* Those listbase data change every time we add/remove an ID, and also often when * renaming one (due to re-sorting). This avoids generating a lot of false 'is changed' * detections between undo steps. */ ((ID *)id_buffer)->prev = NULL; ((ID *)id_buffer)->next = NULL; + /* Those runtime pointers should never be set during writing stage, but just in case clear + * them too. */ + ((ID *)id_buffer)->orig_id = NULL; + ((ID *)id_buffer)->newid = NULL; + /* Even though in theory we could be able to preserve this python instance across undo even + * when we need to re-read the ID into its original address, this is currently cleared in + * #direct_link_id_common in `readfile.c` anyway, */ + ((ID *)id_buffer)->py_instance = NULL; const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); if (id_type->blend_write != NULL) { -- cgit v1.2.3 From 46aafbbf6683d20c57f3668d04ce1cf6cd14e0e8 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 19 Aug 2021 09:52:09 -0300 Subject: Cleanup: move animation snap utilities to a separate compilation unit The snap functions of animation editors were scattered in `transform_mode` and `transform_snap`. --- source/blender/editors/transform/CMakeLists.txt | 1 + .../editors/transform/transform_convert_graph.c | 2 + .../editors/transform/transform_convert_nla.c | 2 + source/blender/editors/transform/transform_mode.c | 96 ------------- source/blender/editors/transform/transform_mode.h | 3 - .../editors/transform/transform_mode_timescale.c | 2 + source/blender/editors/transform/transform_snap.c | 40 +----- source/blender/editors/transform/transform_snap.h | 17 ++- .../editors/transform/transform_snap_animation.c | 156 +++++++++++++++++++++ 9 files changed, 175 insertions(+), 144 deletions(-) create mode 100644 source/blender/editors/transform/transform_snap_animation.c (limited to 'source/blender') diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index ad0a330f0f4..e9efed3cd61 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -101,6 +101,7 @@ set(SRC transform_ops.c transform_orientations.c transform_snap.c + transform_snap_animation.c transform_snap_object.c transform_snap_sequencer.c diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index a6cbbb299ac..c0acdd89b02 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -41,6 +41,8 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_snap.h" + #include "transform_mode.h" typedef struct TransDataGraph { diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index f96f2e93bbc..4d98b7a489f 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -42,6 +42,8 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_snap.h" + #include "transform_mode.h" /** Used for NLA transform (stored in #TransData.extra pointer). */ diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 362ee179e7d..8df95222fa1 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1067,102 +1067,6 @@ void ElementResize(const TransInfo *t, /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Transform (Frame Utils) - * \{ */ - -/** - * This function returns the snapping 'mode' for Animation Editors only. - * We cannot use the standard snapping due to NLA-strip scaling complexities. - * - * TODO: these modifier checks should be key-mappable. - */ -short getAnimEdit_SnapMode(TransInfo *t) -{ - short autosnap = SACTSNAP_OFF; - - if (t->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; - - if (saction) { - autosnap = saction->autosnap; - } - } - else if (t->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; - - if (sipo) { - autosnap = sipo->autosnap; - } - } - else if (t->spacetype == SPACE_NLA) { - SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; - - if (snla) { - autosnap = snla->autosnap; - } - } - else { - autosnap = SACTSNAP_OFF; - } - - /* toggle autosnap on/off - * - when toggling on, prefer nearest frame over 1.0 frame increments - */ - if (t->modifiers & MOD_SNAP_INVERT) { - if (autosnap) { - autosnap = SACTSNAP_OFF; - } - else { - autosnap = SACTSNAP_FRAME; - } - } - - return autosnap; -} - -/* This function is used by Animation Editor specific transform functions to do - * the Snap Keyframe to Nearest Frame/Marker - */ -void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) -{ - if (autosnap != SACTSNAP_OFF) { - float val; - - /* convert frame to nla-action time (if needed) */ - if (adt && (t->spacetype != SPACE_SEQ)) { - val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); - } - else { - val = *(td->val); - } - - snapFrameTransform(t, autosnap, true, val, &val); - - /* convert frame out of nla-action time */ - if (adt && (t->spacetype != SPACE_SEQ)) { - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - *(td->val) = val; - } - } - - /* If the handles are to be moved too - * (as side-effect of keyframes moving, to keep the general effect) - * offset them by the same amount so that the general angles are maintained - * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). - */ - if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { - td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival; - } - if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { - td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival; - } -} -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Transform Mode Initialization * \{ */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 027fb6b6982..d8601000ddb 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -63,9 +63,6 @@ void ElementResize(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3]); -short getAnimEdit_SnapMode(TransInfo *t); -void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); void transform_mode_default_modal_orientation_set(TransInfo *t, int type); diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c index 98ffc0abbd4..4123663e849 100644 --- a/source/blender/editors/transform/transform_mode_timescale.c +++ b/source/blender/editors/transform/transform_mode_timescale.c @@ -40,6 +40,8 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_snap.h" + #include "transform_mode.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 656a1e5d9c7..ea08c8912e9 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1461,47 +1461,9 @@ bool snapNodesTransform( /** \} */ /* -------------------------------------------------------------------- */ -/** \name snap Frames +/** \name snap Grid * \{ */ -/* This function is used by Animation Editor specific transform functions to do - * the Snap Keyframe to Nearest Frame/Marker - */ -void snapFrameTransform(TransInfo *t, - const eAnimEdit_AutoSnap autosnap, - const bool is_frame_value, - const float delta, - float *r_val) -{ - double val = delta; - switch (autosnap) { - case SACTSNAP_STEP: - case SACTSNAP_FRAME: - val = floor(val + 0.5); - break; - case SACTSNAP_MARKER: - /* snap to nearest marker */ - /* TODO: need some more careful checks for where data comes from. */ - val = ED_markers_find_nearest_marker_time(&t->scene->markers, (float)val); - break; - case SACTSNAP_SECOND: - case SACTSNAP_TSTEP: { - /* second step */ - const Scene *scene = t->scene; - const double secf = FPS; - val = floor((val / secf) + 0.5); - if (is_frame_value) { - val *= secf; - } - break; - } - case SACTSNAP_OFF: { - break; - } - } - *r_val = (float)val; -} - static void snap_grid_apply( TransInfo *t, const int max_index, const float grid_dist, const float loc[3], float r_out[3]) { diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 6dfaeab93e6..20cc590d7cc 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -45,12 +45,6 @@ bool snapNodesTransform(struct TransInfo *t, float r_loc[2], float *r_dist_px, char *r_node_border); -void snapFrameTransform(struct TransInfo *t, - const eAnimEdit_AutoSnap autosnap, - const bool is_frame_value, - const float delta, - /* return args */ - float *r_val); bool transformModeUseSnap(const TransInfo *t); @@ -86,3 +80,14 @@ struct TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t) void transform_snap_sequencer_data_free(struct TransSeqSnapData *data); bool transform_snap_sequencer_calc(struct TransInfo *t); void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec); + +/* transform_snap_animation.c */ +short getAnimEdit_SnapMode(TransInfo *t); +void snapFrameTransform(struct TransInfo *t, + const eAnimEdit_AutoSnap autosnap, + const bool is_frame_value, + const float delta, + /* return args */ + float *r_val); +void doAnimEdit_SnapFrame( + TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c new file mode 100644 index 00000000000..ac7c47e408f --- /dev/null +++ b/source/blender/editors/transform/transform_snap_animation.c @@ -0,0 +1,156 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup edtransform + */ + +#include "DNA_anim_types.h" + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_nla.h" + +#include "ED_markers.h" +#include "ED_screen.h" + +#include "transform.h" +#include "transform_snap.h" + +/* -------------------------------------------------------------------- */ +/** \name Snappint in Anim Editors + * \{ */ + +/** + * This function returns the snapping 'mode' for Animation Editors only. + * We cannot use the standard snapping due to NLA-strip scaling complexities. + * + * TODO: these modifier checks should be key-mappable. + */ +short getAnimEdit_SnapMode(TransInfo *t) +{ + short autosnap = SACTSNAP_OFF; + + if (t->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)t->area->spacedata.first; + + if (saction) { + autosnap = saction->autosnap; + } + } + else if (t->spacetype == SPACE_GRAPH) { + SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first; + + if (sipo) { + autosnap = sipo->autosnap; + } + } + else if (t->spacetype == SPACE_NLA) { + SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; + + if (snla) { + autosnap = snla->autosnap; + } + } + else { + autosnap = SACTSNAP_OFF; + } + + /* toggle autosnap on/off + * - when toggling on, prefer nearest frame over 1.0 frame increments + */ + if (t->modifiers & MOD_SNAP_INVERT) { + if (autosnap) { + autosnap = SACTSNAP_OFF; + } + else { + autosnap = SACTSNAP_FRAME; + } + } + + return autosnap; +} + +void snapFrameTransform(TransInfo *t, + const eAnimEdit_AutoSnap autosnap, + const bool is_frame_value, + const float delta, + /* return args */ + float *r_val) +{ + double val = delta; + switch (autosnap) { + case SACTSNAP_STEP: + case SACTSNAP_FRAME: + val = floor(val + 0.5); + break; + case SACTSNAP_MARKER: + /* snap to nearest marker */ + /* TODO: need some more careful checks for where data comes from. */ + val = ED_markers_find_nearest_marker_time(&t->scene->markers, (float)val); + break; + case SACTSNAP_SECOND: + case SACTSNAP_TSTEP: { + /* second step */ + const Scene *scene = t->scene; + const double secf = FPS; + val = floor((val / secf) + 0.5); + if (is_frame_value) { + val *= secf; + } + break; + } + case SACTSNAP_OFF: { + break; + } + } + *r_val = (float)val; +} + +/* This function is used by Animation Editor specific transform functions to do + * the Snap Keyframe to Nearest Frame/Marker + */ +void doAnimEdit_SnapFrame( + TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) +{ + if (autosnap != SACTSNAP_OFF) { + float val; + + /* convert frame to nla-action time (if needed) */ + if (adt && (t->spacetype != SPACE_SEQ)) { + val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); + } + else { + val = *(td->val); + } + + snapFrameTransform(t, autosnap, true, val, &val); + + /* convert frame out of nla-action time */ + if (adt && (t->spacetype != SPACE_SEQ)) { + *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); + } + else { + *(td->val) = val; + } + } +} + +/** \} */ -- cgit v1.2.3 From 85b044b3ef593fb4df5a9b3ca4f5a087587228f4 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 18 Aug 2021 11:02:24 -0300 Subject: Fix incremental snap in animation editors Animation editors have their own snap types and incremental is not supported. --- source/blender/editors/transform/transform_snap.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index ea08c8912e9..05a20a14477 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -594,7 +594,7 @@ static void initSnappingMode(TransInfo *t) else if (t->spacetype == SPACE_SEQ) { t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene); } - else { + else if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { /* force project off when not supported */ if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) { t->tsnap.project = 0; @@ -608,6 +608,14 @@ static void initSnappingMode(TransInfo *t) t->tsnap.mode |= SCE_SNAP_MODE_GRID; } } + else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) { + /* No incremental snapping. */ + t->tsnap.mode = 0; + } + else { + /* Fallback. */ + t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + } if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { /* Only 3D view or UV. */ @@ -654,10 +662,6 @@ static void initSnappingMode(TransInfo *t) setSnappingCallback(t); t->tsnap.modeSelect = SNAP_NOT_SELECTED; } - else { - /* Fallback. */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; - } if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { -- cgit v1.2.3 From 119d53263f0d0dc5474cb36e888dbdd48a64f9c6 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 19 Aug 2021 10:23:35 -0300 Subject: Transform Convert Action: conventionalize TransData creation `td2d->loc`, `td2d->loc2d`, `td->loc` and `td->iloc` were not being initialized as is done with the other conversion types. This avoids problems with transform modes becoming incompatible. This avoids problems with incompatible transform modes that could result in a crash. --- .../editors/transform/transform_convert_action.c | 46 ++++++++++++---------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index cfa14e21d0d..30cb9fa20e5 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -140,19 +140,37 @@ static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, boo } /* This function assigns the information to transdata */ -static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos) +static void TimeToTransData( + TransData *td, TransData2D *td2d, BezTriple *bezt, AnimData *adt, float ypos) { - /* memory is calloc'ed, so that should zero everything nicely for us */ + float *time = bezt->vec[1]; + + /* Setup #TransData2D. */ + td2d->loc[0] = *time; + td2d->loc2d = time; + td2d->h1 = bezt->vec[0]; + td2d->h2 = bezt->vec[2]; + copy_v2_v2(td2d->ih1, td2d->h1); + copy_v2_v2(td2d->ih2, td2d->h2); + + /* Setup #TransData. */ + td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is + not float[3]. */ td->val = time; - td->ival = *(time); - + td->ival = td->iloc[0] = *(time); td->center[0] = td->ival; td->center[1] = ypos; - /* store the AnimData where this keyframe exists as a keyframe of the - * active action as td->extra. - */ + /* Store the AnimData where this keyframe exists as a keyframe of the + * active action as #td->extra. */ td->extra = adt; + + if (bezt->f2 & SELECT) { + td->flag |= TD_SELECTED; + } + + /* Set flags to move handles as necessary. */ + td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2; } /* This function advances the address to which td points to, so it must return @@ -185,19 +203,7 @@ static TransData *ActionFCurveToTransData(TransData *td, * so can't use BEZT_ISSEL_ANY() macro */ /* only add if on the right 'side' of the current frame */ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { - TimeToTransData(td, bezt->vec[1], adt, ypos); - - if (bezt->f2 & SELECT) { - td->flag |= TD_SELECTED; - } - - /* Set flags to move handles as necessary. */ - td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2; - td2d->h1 = bezt->vec[0]; - td2d->h2 = bezt->vec[2]; - - copy_v2_v2(td2d->ih1, td2d->h1); - copy_v2_v2(td2d->ih2, td2d->h2); + TimeToTransData(td, td2d, bezt, adt, ypos); td++; td2d++; -- cgit v1.2.3 From b0d9e6797fb866e7a58876c7977c98a190070310 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 19 Aug 2021 10:28:43 -0300 Subject: Fix T87173: wrong Auto-Snap in animation editors This was partially broken with {rBde9ea94fc6f}. The `Frame Step` and `Second Step` snapping options were working as if they were `Nearest Frame` and `Nearest Second` respectively in the `Dope Sheet` and `NLA` editors. In the `Graph Editor` the problem was more serious: "Second Step: ... The keyframe itself moves along as though in snapping were active at all, while its handles 'stay behind' until it reaches the next second boundary, at which point the teleport handles to 'catch up'". The snapping code for these modes was spread across the transform mode code and `recalcData` of each data type. Therefore, create a unified snapping code for these options so that all issues are fixed in one place. Differetial Revision: https://developer.blender.org/D12241 --- .../blender/editors/transform/transform_convert.c | 17 +++++ .../blender/editors/transform/transform_convert.h | 3 + .../editors/transform/transform_convert_action.c | 15 +++++ .../editors/transform/transform_convert_graph.c | 59 ++--------------- .../editors/transform/transform_convert_nla.c | 71 ++++++--------------- .../editors/transform/transform_mode_timescale.c | 4 -- .../transform/transform_mode_timetranslate.c | 33 +++++----- source/blender/editors/transform/transform_snap.h | 15 ++--- .../editors/transform/transform_snap_animation.c | 73 +++++++++++----------- 9 files changed, 119 insertions(+), 171 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 3f730956dd0..094ae080de0 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1662,6 +1662,23 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) } } +void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float inv_unit_scale) +{ + /* If the handles are to be moved too + * (as side-effect of keyframes moving, to keep the general effect) + * offset them by the same amount so that the general angles are maintained + * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked). + */ + if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { + td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0]; + td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; + } + if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { + td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0]; + td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; + } +} + /* called for updating while transform acts, once per redraw */ void recalcData(TransInfo *t) { diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 55731bfa321..fa34e2555d6 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -43,6 +43,9 @@ void sort_trans_data_dist(TransInfo *t); void createTransData(struct bContext *C, TransInfo *t); bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); void clipUVData(TransInfo *t); +void transform_convert_flush_handle2D(TransData *td, + TransData2D *td2d, + const float inv_unit_scale); void recalcData(TransInfo *t); /* transform_convert_mesh.c */ diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index 30cb9fa20e5..8a3b254be5c 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -45,6 +45,8 @@ #include "WM_types.h" #include "transform.h" +#include "transform_snap.h" + #include "transform_convert.h" /* helper struct for gp-frame transforms */ @@ -604,6 +606,19 @@ void recalcData_actedit(TransInfo *t) flushTransIntFrameActionData(t); } + /* Flush 2d vector. */ + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + const short autosnap = getAnimEdit_SnapMode(t); + TransData *td; + TransData2D *td2d; + int i = 0; + for (td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) { + if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) { + transform_snap_anim_flush_data(t, td, autosnap, td->loc); + } + transform_convert_flush_handle2D(td, td2d, 1.0f); + } + if (ac.datatype != ANIMCONT_MASK) { /* Get animdata blocks visible in editor, * assuming that these will be the ones where things changed. */ diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index c0acdd89b02..d22277f9d91 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -40,6 +40,8 @@ #include "UI_view2d.h" #include "transform.h" +#include "transform_snap.h" + #include "transform_convert.h" #include "transform_snap.h" @@ -662,10 +664,9 @@ static void flushTransGraphData(TransInfo *t) TransData *td; TransData2D *td2d; TransDataGraph *tdg; - Scene *scene = t->scene; - double secf = FPS; int a; + const short autosnap = getAnimEdit_SnapMode(t); TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); /* flush to 2d vector from internally used 3d vector */ @@ -681,22 +682,8 @@ static void flushTransGraphData(TransInfo *t) * - Only apply to keyframes (but never to handles). * - Don't do this when canceling, or else these changes won't go away. */ - if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) { - const short autosnap = getAnimEdit_SnapMode(t); - switch (autosnap) { - case SACTSNAP_FRAME: /* snap to nearest frame */ - td2d->loc[0] = floor((double)td2d->loc[0] + 0.5); - break; - - case SACTSNAP_SECOND: /* snap to nearest second */ - td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf; - break; - - case SACTSNAP_MARKER: /* snap to nearest marker */ - td2d->loc[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, - td2d->loc[0]); - break; - } + if ((autosnap != SACTSNAP_OFF) && (t->state != TRANS_CANCEL) && !(td->flag & TD_NOTIMESNAP)) { + transform_snap_anim_flush_data(t, td, autosnap, td->loc); } /* we need to unapply the nla-mapping from the time in some situations */ @@ -707,32 +694,6 @@ static void flushTransGraphData(TransInfo *t) td2d->loc2d[0] = td2d->loc[0]; } - /** Time-stepping auto-snapping modes don't get applied for Graph Editor transforms, - * as these use the generic transform modes which don't account for this sort of thing. - * These ones aren't affected by NLA mapping, so we do this after the conversion... - * - * \note We also have to apply to td->loc, - * as that's what the handle-adjustment step below looks to, - * otherwise we get "swimming handles". - * - * \note We don't do this when canceling transforms, or else these changes don't go away. - */ - if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) { - const short autosnap = getAnimEdit_SnapMode(t); - switch (autosnap) { - case SACTSNAP_STEP: /* frame step */ - td2d->loc2d[0] = floor((double)td2d->loc[0] + 0.5); - td->loc[0] = floor((double)td->loc[0] + 0.5); - break; - - case SACTSNAP_TSTEP: /* second step */ - /* XXX: the handle behavior in this case is still not quite right... */ - td2d->loc[0] = floor(((double)td2d->loc[0] / secf) + 0.5) * secf; - td->loc[0] = floor(((double)td->loc[0] / secf) + 0.5) * secf; - break; - } - } - /* if int-values only, truncate to integers */ if (td->flag & TD_INTVALUES) { td2d->loc2d[1] = floorf(td2d->loc[1] * inv_unit_scale - tdg->offset + 0.5f); @@ -741,15 +702,7 @@ static void flushTransGraphData(TransInfo *t) td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset; } - if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { - td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0]; - td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; - } - - if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { - td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0]; - td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale; - } + transform_convert_flush_handle2D(td, td2d, inv_unit_scale); } } diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index 4d98b7a489f..7e5b80c2453 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -41,6 +41,8 @@ #include "RNA_access.h" #include "transform.h" +#include "transform_snap.h" + #include "transform_convert.h" #include "transform_snap.h" @@ -292,21 +294,30 @@ void createTransNlaData(bContext *C, TransInfo *t) void recalcData_nla(TransInfo *t) { SpaceNla *snla = (SpaceNla *)t->area->spacedata.first; - Scene *scene = t->scene; - double secf = FPS; - int i; TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); - TransDataNla *tdn = tc->custom.type.data; + + /* handle auto-snapping + * NOTE: only do this when transform is still running, or we can't restore + */ + if (t->state != TRANS_CANCEL) { + const short autosnap = getAnimEdit_SnapMode(t); + if (autosnap != SACTSNAP_OFF) { + TransData *td = tc->data; + for (int i = 0; i < tc->data_len; i++, td++) { + transform_snap_anim_flush_data(t, td, autosnap, td->loc); + } + } + } /* For each strip we've got, perform some additional validation of the values * that got set before using RNA to set the value (which does some special * operations when setting these values to make sure that everything works ok). */ - for (i = 0; i < tc->data_len; i++, tdn++) { + TransDataNla *tdn = tc->custom.type.data; + for (int i = 0; i < tc->data_len; i++, tdn++) { NlaStrip *strip = tdn->strip; PointerRNA strip_ptr; - short iter; int delta_y1, delta_y2; /* if this tdn has no handles, that means it is just a dummy that should be skipped */ @@ -370,8 +381,7 @@ void recalcData_nla(TransInfo *t) next = next->next; } - for (iter = 0; iter < 5; iter++) { - + for (short iter = 0; iter < 5; iter++) { const bool pExceeded = (prev != NULL) && (tdn->h1[0] < prev->end); const bool nExceeded = (next != NULL) && (tdn->h2[0] > next->start); @@ -410,51 +420,6 @@ void recalcData_nla(TransInfo *t) } } - /* handle auto-snapping - * NOTE: only do this when transform is still running, or we can't restore - */ - if (t->state != TRANS_CANCEL) { - const short autosnap = getAnimEdit_SnapMode(t); - switch (autosnap) { - case SACTSNAP_FRAME: /* snap to nearest frame */ - case SACTSNAP_STEP: /* frame step - this is basically the same, - * since we don't have any remapping going on */ - { - tdn->h1[0] = floorf(tdn->h1[0] + 0.5f); - tdn->h2[0] = floorf(tdn->h2[0] + 0.5f); - break; - } - - case SACTSNAP_SECOND: /* snap to nearest second */ - case SACTSNAP_TSTEP: /* second step - this is basically the same, - * since we don't have any remapping going on */ - { - /* This case behaves differently from the rest, since lengths of strips - * may not be multiples of a second. If we just naively resize adjust - * the handles, things may not work correctly. Instead, we only snap - * the first handle, and move the other to fit. - * - * FIXME: we do run into problems here when user attempts to negatively - * scale the strip, as it then just compresses down and refuses - * to expand out the other end. - */ - float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf); - float delta = h1_new - tdn->h1[0]; - - tdn->h1[0] = h1_new; - tdn->h2[0] += delta; - break; - } - - case SACTSNAP_MARKER: /* snap to nearest marker */ - { - tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]); - tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]); - break; - } - } - } - /* Use RNA to write the values to ensure that constraints on these are obeyed * (e.g. for transition strips, the values are taken from the neighbors) * diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c index 4123663e849..50fd714727b 100644 --- a/source/blender/editors/transform/transform_mode_timescale.c +++ b/source/blender/editors/transform/transform_mode_timescale.c @@ -65,7 +65,6 @@ static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR]) static void applyTimeScaleValue(TransInfo *t, float value) { Scene *scene = t->scene; - const short autosnap = getAnimEdit_SnapMode(t); FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; @@ -89,9 +88,6 @@ static void applyTimeScaleValue(TransInfo *t, float value) /* now, calculate the new value */ *(td->val) = ((td->ival - startx) * fac) + startx; - - /* apply nearest snapping */ - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); } } } diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c index 01b9a08cf27..294040946bd 100644 --- a/source/blender/editors/transform/transform_mode_timetranslate.c +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -59,10 +59,18 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) } else { const short autosnap = getAnimEdit_SnapMode(t); - float val = t->values_final[0]; + float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; + float val = ival + t->values_final[0]; - float snap_val; - snapFrameTransform(t, autosnap, false, val, &snap_val); + float snap_val = val; + snapFrameTransform(t, autosnap, ival, val, &snap_val); + + if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) { + /* Convert to seconds. */ + const Scene *scene = t->scene; + const double secf = FPS; + snap_val /= secf; + } if (autosnap == SACTSNAP_FRAME) { BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); @@ -88,24 +96,11 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) static void applyTimeTranslateValue(TransInfo *t, const float deltax) { - const short autosnap = getAnimEdit_SnapMode(t); - FOREACH_TRANS_DATA_CONTAINER (t, tc) { + /* It doesn't matter whether we apply to t->data. */ TransData *td = tc->data; - TransData2D *td2d = tc->data_2d; - /* It doesn't matter whether we apply to t->data or - * t->data2d, but t->data2d is more convenient. */ - for (int i = 0; i < tc->data_len; i++, td++, td2d++) { - /* It is assumed that td->extra is a pointer to the AnimData, - * whose active action is where this keyframe comes from. - * (this is only valid when not in NLA) - * (also: masks and gpencil don't have animadata) - */ - AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL; - - /* apply nearest snapping */ - *(td->val) = td->ival + deltax * td->factor; - doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); + for (int i = 0; i < tc->data_len; i++, td++) { + *(td->val) = td->loc[0] = td->ival + deltax * td->factor; } } } diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 20cc590d7cc..ed7f93304bc 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -83,11 +83,12 @@ void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec); /* transform_snap_animation.c */ short getAnimEdit_SnapMode(TransInfo *t); -void snapFrameTransform(struct TransInfo *t, +void snapFrameTransform(TransInfo *t, const eAnimEdit_AutoSnap autosnap, - const bool is_frame_value, - const float delta, - /* return args */ - float *r_val); -void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); + const float val_initial, + const float val_final, + float *r_val_final); +void transform_snap_anim_flush_data(TransInfo *t, + TransData *td, + const eAnimEdit_AutoSnap autosnap, + float *r_val_final); diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c index ac7c47e408f..be7fc65a6c2 100644 --- a/source/blender/editors/transform/transform_snap_animation.c +++ b/source/blender/editors/transform/transform_snap_animation.c @@ -90,67 +90,70 @@ short getAnimEdit_SnapMode(TransInfo *t) void snapFrameTransform(TransInfo *t, const eAnimEdit_AutoSnap autosnap, - const bool is_frame_value, - const float delta, - /* return args */ - float *r_val) + const float val_initial, + const float val_final, + float *r_val_final) { - double val = delta; + float deltax = val_final - val_initial; switch (autosnap) { - case SACTSNAP_STEP: case SACTSNAP_FRAME: - val = floor(val + 0.5); + *r_val_final = floorf(val_final + 0.5f); break; case SACTSNAP_MARKER: - /* snap to nearest marker */ + /* Snap to nearest marker. */ /* TODO: need some more careful checks for where data comes from. */ - val = ED_markers_find_nearest_marker_time(&t->scene->markers, (float)val); + *r_val_final = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, val_final); break; case SACTSNAP_SECOND: case SACTSNAP_TSTEP: { - /* second step */ const Scene *scene = t->scene; const double secf = FPS; - val = floor((val / secf) + 0.5); - if (is_frame_value) { - val *= secf; + if (autosnap == SACTSNAP_SECOND) { + *r_val_final = floorf((val_final / secf) + 0.5) * secf; + } + else { + deltax = (float)(floor((deltax / secf) + 0.5) * secf); + *r_val_final = val_initial + deltax; } break; } - case SACTSNAP_OFF: { + case SACTSNAP_STEP: + deltax = floorf(deltax + 0.5f); + *r_val_final = val_initial + deltax; + break; + case SACTSNAP_OFF: break; - } } - *r_val = (float)val; } /* This function is used by Animation Editor specific transform functions to do * the Snap Keyframe to Nearest Frame/Marker */ -void doAnimEdit_SnapFrame( - TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) +void transform_snap_anim_flush_data(TransInfo *t, + TransData *td, + const eAnimEdit_AutoSnap autosnap, + float *r_val_final) { - if (autosnap != SACTSNAP_OFF) { - float val; + BLI_assert(autosnap != SACTSNAP_OFF); - /* convert frame to nla-action time (if needed) */ - if (adt && (t->spacetype != SPACE_SEQ)) { - val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); - } - else { - val = *(td->val); - } + float val = td->loc[0]; + float ival = td->iloc[0]; + AnimData *adt = (!ELEM(t->spacetype, SPACE_NLA, SPACE_SEQ)) ? td->extra : NULL; - snapFrameTransform(t, autosnap, true, val, &val); + /* Convert frame to nla-action time (if needed) */ + if (adt) { + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP); + ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP); + } - /* convert frame out of nla-action time */ - if (adt && (t->spacetype != SPACE_SEQ)) { - *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); - } - else { - *(td->val) = val; - } + snapFrameTransform(t, autosnap, ival, val, &val); + + /* Convert frame out of nla-action time. */ + if (adt) { + val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); } + + *r_val_final = val; } /** \} */ -- cgit v1.2.3 From 7192e57d63a53a96461ba3ea761240f25a4294b7 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 19 Aug 2021 10:31:13 -0300 Subject: Fix the value in the graphical editor header when transforming The header did not display the actual value when transforming with snapping --- .../editors/transform/transform_mode_translate.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 75744f26c15..e44e346d3e4 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -221,22 +221,30 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } else { float dvec[3]; + copy_v3_v3(dvec, vec); + if (t->spacetype == SPACE_GRAPH) { + /* WORKAROUND: + * Special case where snapping is done in #recalData. + * Update the header based on the first element. */ + const short autosnap = getAnimEdit_SnapMode(t); + float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; + float val = ival + dvec[0]; + snapFrameTransform(t, autosnap, ival, val, &dvec[0]); + } + if (t->con.mode & CON_APPLY) { int i = 0; zero_v3(dvec); if (t->con.mode & CON_AXIS0) { - dvec[i++] = vec[0]; + dvec[i++] = dvec[0]; } if (t->con.mode & CON_AXIS1) { - dvec[i++] = vec[1]; + dvec[i++] = dvec[1]; } if (t->con.mode & CON_AXIS2) { - dvec[i++] = vec[2]; + dvec[i++] = dvec[2]; } } - else { - copy_v3_v3(dvec, vec); - } if (t->flag & T_2D_EDIT) { applyAspectRatio(t, dvec); -- cgit v1.2.3 From 71655ff8dfae7eb63a237f03bea414ff4ebc5714 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 19 Aug 2021 16:59:01 +0200 Subject: GPencil: Match row color for Summary in Grease Pencil animation editor The background of the summary row was different in Grease Pencil mode. Reviewed by: Pablo Vazquez, Matias Mendiola --- source/blender/editors/space_action/action_draw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 903754f4fb1..0a143c35a2a 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -144,12 +144,14 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region uchar col1[4], col2[4]; uchar col1a[4], col2a[4]; uchar col1b[4], col2b[4]; + uchar col_summary[4]; const bool show_group_colors = U.animation_flag & USER_ANIM_SHOW_CHANNEL_GROUP_COLORS; /* get theme colors */ UI_GetThemeColor4ubv(TH_SHADE2, col2); UI_GetThemeColor4ubv(TH_HILITE, col1); + UI_GetThemeColor4ubv(TH_ANIM_ACTIVE, col_summary); UI_GetThemeColor4ubv(TH_GROUP, col2a); UI_GetThemeColor4ubv(TH_GROUP_ACTIVE, col1a); @@ -244,7 +246,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region else if (ac->datatype == ANIMCONT_GPENCIL) { uchar *color; uchar gpl_col[4]; - if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) { + if (ale->type == ANIMTYPE_SUMMARY) { + color = col_summary; + color[3] = col1[3]; + } + else if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) { bGPDlayer *gpl = (bGPDlayer *)ale->data; rgb_float_to_uchar(gpl_col, gpl->color); gpl_col[3] = col1[3]; -- cgit v1.2.3 From 479cc9a83eeb67cf0076384b378b50ec86cd8d5c Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 19 Aug 2021 17:02:42 +0200 Subject: UI: Match row color for Summary in Mask animation editor The back color of the row was missing. --- source/blender/editors/space_action/action_draw.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 0a143c35a2a..a15f3507d7e 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -271,7 +271,14 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region else if (ac->datatype == ANIMCONT_MASK) { /* TODO: this is a copy of gpencil. */ /* frames less than one get less saturated background */ - uchar *color = sel ? col1 : col2; + uchar *color; + if (ale->type == ANIMTYPE_SUMMARY) { + color = col_summary; + color[3] = col1[3]; + } + else { + color = sel ? col1 : col2; + } immUniformColor4ubv(color); immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax); -- cgit v1.2.3 From 0896457c59d722e809188517c042b57d0ea399d3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Aug 2021 17:04:19 +0200 Subject: Partially fix T90593: Image ID wrongly seen as changed on undos. Several pure runtime data in this ID type were not properly cleared by write/read processes. Note that the initial undo step (the one leading back to initial read file state) is still forcing re-load of image, for some reasons. Common investigation together with Jeroen Bakker (@jbakker), thanks. See also D12242. --- source/blender/blenkernel/intern/image.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index de9f2a5a656..f37073ff135 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -230,6 +230,19 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres Image *ima = (Image *)id; const bool is_undo = BLO_write_is_undo(writer); + /* Clear all data that isn't read to reduce false detection of changed image during memfile undo. + */ + ima->lastused = 0; + ima->cache = NULL; + ima->gpuflag = 0; + BLI_listbase_clear(&ima->anims); + BLI_listbase_clear(&ima->gpu_refresh_areas); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + ima->gputexture[i][j] = NULL; + } + } + ImagePackedFile *imapf; BLI_assert(ima->packedfile == NULL); @@ -299,6 +312,7 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { tile->ok = IMA_OK; } + ima->lastused = 0; ima->gpuflag = 0; BLI_listbase_clear(&ima->gpu_refresh_areas); } -- cgit v1.2.3 From 3febcb98ed4cbf65d7e6386fd3bc5ece2ad903bc Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 19 Aug 2021 17:35:04 +0200 Subject: Image blendwrite: Fix handling of packedfiles. Packedfiles need some special attention when writing Image to disk. Source: D12242, Jeroen Bakker (@jbakker), thanks. --- source/blender/blenkernel/intern/image.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f37073ff135..5701449a9e5 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -246,15 +246,17 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres ImagePackedFile *imapf; BLI_assert(ima->packedfile == NULL); - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) { - BLI_listbase_clear(&ima->packedfiles); - } - else { - /* Some trickery to keep forward compatibility of packed images. */ - if (ima->packedfiles.first != NULL) { - imapf = ima->packedfiles.first; - ima->packedfile = imapf->packedfile; + if (!is_undo) { + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(ima)) { + BLI_listbase_clear(&ima->packedfiles); + } + else { + /* Some trickery to keep forward compatibility of packed images. */ + if (ima->packedfiles.first != NULL) { + imapf = ima->packedfiles.first; + ima->packedfile = imapf->packedfile; + } } } -- cgit v1.2.3 From 871f7f4ad8326a944bc96251179c8885986d7ef7 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 19 Aug 2021 19:23:01 +0200 Subject: GPencil: Cleanup old printf debug lines These lines were very old debug code and now it's not required because the code is very tested. --- source/blender/editors/gpencil/annotate_paint.c | 85 ---------------------- source/blender/editors/gpencil/gpencil_convert.c | 25 ------- source/blender/editors/gpencil/gpencil_paint.c | 54 -------------- source/blender/editors/gpencil/gpencil_primitive.c | 5 -- source/blender/editors/gpencil/gpencil_undo.c | 2 - 5 files changed, 171 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 31ef094afa6..bf47704746b 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -836,10 +836,6 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) /* exit with error if no valid points from this stroke */ if (totelem == 0) { - if (G.debug & G_DEBUG) { - printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", - gpd->runtime.sbuffer_used); - } return; } @@ -1263,9 +1259,6 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p) /* make sure the active view (at the starting time) is a 3d-view */ if (curarea == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: No active view for painting\n"); - } return 0; } @@ -1294,11 +1287,6 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p) if (region->regiondata == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf( - "Error: 3D-View active region doesn't have any region data, so cannot be " - "drawable\n"); - } return 0; } break; @@ -1325,9 +1313,6 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p) /* check that gpencil data is allowed to be drawn */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n"); - } return 0; } break; @@ -1387,9 +1372,6 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p) /* unsupported views */ default: { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Annotations are not supported in this editor\n"); - } return 0; } } @@ -1398,9 +1380,6 @@ static bool annotation_session_initdata(bContext *C, tGPsdata *p) gpd_ptr = ED_annotation_data_get_pointers(C, &p->ownerPtr); if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Current context doesn't allow for any Annotation data\n"); - } return 0; } @@ -1507,7 +1486,6 @@ static void annotation_session_cleanup(tGPsdata *p) /* free stroke buffer */ if (gpd->runtime.sbuffer) { - // printf("\t\tGP - free sbuffer\n"); MEM_freeN(gpd->runtime.sbuffer); gpd->runtime.sbuffer = NULL; } @@ -1545,9 +1523,6 @@ static void annotation_paint_initstroke(tGPsdata *p, } if (p->gpl->flag & GP_LAYER_LOCKED) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Cannot paint on locked layer\n"); - } return; } @@ -1573,7 +1548,6 @@ static void annotation_paint_initstroke(tGPsdata *p, if (has_layer_to_erase == false) { p->status = GP_STATUS_CAPTURE; - // if (G.debug & G_DEBUG) printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n"); return; } @@ -1593,9 +1567,6 @@ static void annotation_paint_initstroke(tGPsdata *p, if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: No frame created (gpencil_paint_init)\n"); - } return; } @@ -2063,9 +2034,6 @@ static void annotation_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgr BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke"); p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Grease-Pencil Paint - Add Point Invalid\n"); - } return; } @@ -2221,29 +2189,22 @@ static int annotation_draw_exec(bContext *C, wmOperator *op) tGPsdata *p = NULL; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - // printf("GPencil - Starting Re-Drawing\n"); - /* try to initialize context data needed while drawing */ if (!annotation_draw_init(C, op, NULL)) { if (op->customdata) { MEM_freeN(op->customdata); } - // printf("\tGP - no valid data\n"); return OPERATOR_CANCELLED; } p = op->customdata; - // printf("\tGP - Start redrawing stroke\n"); - /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement), * setting the relevant values in context at each step, then applying */ RNA_BEGIN (op->ptr, itemptr, "stroke") { float mousef[2]; - // printf("\t\tGP - stroke elem\n"); - /* get relevant data for this point from stroke */ RNA_float_get_array(&itemptr, "mouse", mousef); p->mval[0] = (int)mousef[0]; @@ -2277,8 +2238,6 @@ static int annotation_draw_exec(bContext *C, wmOperator *op) } RNA_END; - // printf("\tGP - done\n"); - /* cleanup */ annotation_draw_exit(C, op); @@ -2301,18 +2260,11 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER); } - if (G.debug & G_DEBUG) { - printf("GPencil - Starting Drawing\n"); - } - /* try to initialize context data needed while drawing */ if (!annotation_draw_init(C, op, event)) { if (op->customdata) { MEM_freeN(op->customdata); } - if (G.debug & G_DEBUG) { - printf("\tGP - no valid data\n"); - } return OPERATOR_CANCELLED; } @@ -2361,7 +2313,6 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* only start drawing immediately if we're allowed to do so... */ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { /* hotkey invoked - start drawing */ - // printf("\tGP - set first spot\n"); p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ @@ -2370,7 +2321,6 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev } else { /* toolbar invoked - don't start drawing yet... */ - // printf("\tGP - hotkey invoked... waiting for click-drag\n"); op->flag |= OP_IS_MODAL_CURSOR_REGION; } @@ -2399,8 +2349,6 @@ static tGPsdata *annotation_stroke_begin(bContext *C, wmOperator *op) p->status = GP_STATUS_ERROR; } - // printf("\t\tGP - start stroke\n"); - /* we may need to set up paint env again if we're resuming */ /* XXX: watch it with the paintmode! in future, * it'd be nice to allow changing paint-mode when in sketching-sessions */ @@ -2537,8 +2485,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve } } - // printf("\tGP - handle modal event...\n"); - /* Exit painting mode (and/or end current stroke) * * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) @@ -2547,7 +2493,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve if (event->val == KM_PRESS && ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY, EVT_EKEY)) { /* exit() ends the current stroke before cleaning up */ - // printf("\t\tGP - end of paint op + end of stroke\n"); p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } @@ -2571,7 +2516,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve if (sketch) { /* end stroke only, and then wait to resume painting soon */ - // printf("\t\tGP - end stroke only\n"); annotation_stroke_end(op); /* If eraser mode is on, turn it off after the stroke finishes @@ -2602,7 +2546,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } else { - // printf("\t\tGP - end of stroke + op\n"); p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } @@ -2619,18 +2562,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve ARegion *current_region = BKE_area_find_region_xy( p->area, RGN_TYPE_ANY, event->x, event->y); - if (G.debug & G_DEBUG) { - printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n", - current_region, - p->region, - event->x, - event->y, - p->area->totrct.xmin, - p->area->totrct.ymin, - p->area->totrct.xmax, - p->area->totrct.ymax); - } - if (current_region) { /* Assume that since we found the cursor in here, it is in bounds * and that this should be the region that we begin drawing in @@ -2642,10 +2573,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve /* Out of bounds, or invalid in some other way */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - - if (G.debug & G_DEBUG) { - printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__); - } } } else if (p->region) { @@ -2657,10 +2584,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve /* No region */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - - if (G.debug & G_DEBUG) { - printf("%s: No active region found in GP Paint session data\n", __func__); - } } if (in_bounds) { @@ -2719,7 +2642,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve } else { /* event handled, so just tag as running modal */ - // printf("\t\t\t\tGP - add point handled!\n"); estate = OPERATOR_RUNNING_MODAL; } } @@ -2729,7 +2651,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve /* just resize the brush (local version) * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys */ - // printf("\t\tGP - resize eraser\n"); switch (event->type) { case WHEELDOWNMOUSE: /* larger */ case EVT_PADPLUSKEY: @@ -2787,12 +2708,6 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: /* event doesn't need to be handled */ -#if 0 - printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n", - event->type, - event->type == MIDDLEMOUSE, - event->type == MOUSEMOVE); -#endif break; } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index a0a58abc02f..406a7ac77fc 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -389,9 +389,6 @@ static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, *r_tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; gtd->tot_time += *r_tot_gaps_time; - if (G.debug & G_DEBUG) { - printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *r_tot_gaps_time, *nbr_gaps); - } if (gtd->gap_randomness > 0.0f) { BLI_rng_srandom(rng, gtd->seed); } @@ -464,9 +461,6 @@ static void gpencil_stroke_path_animation_add_keyframes(ReportList *reports, INSERTKEY_FAST); last_valid_time = cfra; } - else if (G.debug & G_DEBUG) { - printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx); - } } else if (i == end_stroke_idx) { /* Always try to insert end point of a curve (should be safe enough, anyway...) */ @@ -546,13 +540,6 @@ static void gpencil_stroke_path_animation(bContext *C, act = ED_id_action_ensure(bmain, (ID *)cu); fcu = ED_action_fcurve_ensure(bmain, act, NULL, &ptr, "eval_time", 0); - if (G.debug & G_DEBUG) { - printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); - for (int i = 0; i < gtd->num_points; i++) { - printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); - } - } - if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) { float cfra; @@ -610,10 +597,6 @@ static void gpencil_stroke_path_animation(bContext *C, time_range = (float)(gtd->end_frame - gtd->start_frame); } - if (G.debug & G_DEBUG) { - printf("GP Stroke Path Conversion: Starting keying!\n"); - } - gpencil_stroke_path_animation_add_keyframes( reports, ptr, prop, depsgraph, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time); @@ -623,14 +606,6 @@ static void gpencil_stroke_path_animation(bContext *C, /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ calchandles_fcurve(fcu); - if (G.debug & G_DEBUG) { - printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); - for (int i = 0; i < gtd->num_points; i++) { - printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); - } - printf("\n\n"); - } - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); /* send updates */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 9e96c40b2db..d2dbf6ab2a6 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -976,10 +976,6 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) /* exit with error if no valid points from this stroke */ if (totelem == 0) { - if (G.debug & G_DEBUG) { - printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", - gpd->runtime.sbuffer_used); - } return; } @@ -1949,9 +1945,6 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) /* make sure the active view (at the starting time) is a 3d-view */ if (curarea == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: No active view for painting\n"); - } return 0; } @@ -1980,11 +1973,6 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) if (region->regiondata == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf( - "Error: 3D-View active region doesn't have any region data, so cannot be " - "drawable\n"); - } return 0; } @@ -2010,9 +1998,6 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) /* unsupported views */ default: { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Active view not appropriate for Grease Pencil drawing\n"); - } return 0; } } @@ -2021,9 +2006,6 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr); if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Current context doesn't allow for any Grease Pencil data\n"); - } return 0; } @@ -2147,9 +2129,6 @@ static void gpencil_paint_initstroke(tGPsdata *p, if ((paintmode != GP_PAINTMODE_ERASER) && (p->gpl->flag & GP_LAYER_LOCKED)) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Cannot paint on locked layer\n"); - } return; } @@ -2228,9 +2207,6 @@ static void gpencil_paint_initstroke(tGPsdata *p, if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: No frame created (gpencil_paint_init)\n"); - } if (!IS_AUTOKEY_ON(scene)) { BKE_report(p->reports, RPT_INFO, "No available frame for creating stroke"); } @@ -2824,9 +2800,6 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke"); p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) { - printf("Error: Grease-Pencil Paint - Add Point Invalid\n"); - } return; } @@ -3198,10 +3171,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - if (G.debug & G_DEBUG) { - printf("GPencil - Starting Drawing\n"); - } - /* support for tablets eraser pen */ if (gpencil_is_tablet_eraser_active(event)) { RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER); @@ -3239,9 +3208,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event if (op->customdata) { MEM_freeN(op->customdata); } - if (G.debug & G_DEBUG) { - printf("\tGP - no valid data\n"); - } return OPERATOR_CANCELLED; } @@ -3730,18 +3696,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) ARegion *current_region = BKE_area_find_region_xy( p->area, RGN_TYPE_ANY, event->x, event->y); - if (G.debug & G_DEBUG) { - printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n", - current_region, - p->region, - event->x, - event->y, - p->area->totrct.xmin, - p->area->totrct.ymin, - p->area->totrct.xmax, - p->area->totrct.ymax); - } - if (current_region) { /* Assume that since we found the cursor in here, it is in bounds * and that this should be the region that we begin drawing in @@ -3753,10 +3707,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Out of bounds, or invalid in some other way */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - - if (G.debug & G_DEBUG) { - printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__); - } } } else if (p->region) { @@ -3768,10 +3718,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* No region */ p->status = GP_STATUS_ERROR; estate = OPERATOR_CANCELLED; - - if (G.debug & G_DEBUG) { - printf("%s: No active region found in GP Paint session data\n", __func__); - } } if (in_bounds) { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 7e6ff53de14..894fb83d70e 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1830,11 +1830,6 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) { tgpi->flag = IN_CURVE_EDIT; } - else { - if (G.debug & G_DEBUG) { - printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag); - } - } break; } case EVT_SPACEKEY: /* confirm */ diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index ede1d3eefaa..96e85cc6135 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -133,8 +133,6 @@ void gpencil_undo_push(bGPdata *gpd) { bGPundonode *undo_node; - // printf("\t\tGP - undo push\n"); - if (cur_node) { /* Remove all undone nodes from stack. */ undo_node = cur_node->next; -- cgit v1.2.3 From 72f73c0b71c5378c0d33f0eb83222dc68d93a5ad Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Thu, 19 Aug 2021 20:24:38 +0200 Subject: UI: Use theme's alpha for Summary instead of a hardcoded value --- source/blender/editors/space_action/action_draw.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index a15f3507d7e..a3bdcd2adf5 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -248,7 +248,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region uchar gpl_col[4]; if (ale->type == ANIMTYPE_SUMMARY) { color = col_summary; - color[3] = col1[3]; } else if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) { bGPDlayer *gpl = (bGPDlayer *)ale->data; @@ -274,7 +273,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region uchar *color; if (ale->type == ANIMTYPE_SUMMARY) { color = col_summary; - color[3] = col1[3]; } else { color = sel ? col1 : col2; -- cgit v1.2.3 From 5b51df0f3301ac829e22e2efcc4c81437668bb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 20 Aug 2021 02:30:11 +0200 Subject: Cleanup, format --- source/blender/blenkernel/BKE_modifier.h | 4 +--- source/blender/editors/interface/interface_templates.c | 3 ++- source/blender/modifiers/intern/MOD_volume_displace.cc | 4 +++- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index c5f309570cd..8be563e4c96 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -427,9 +427,7 @@ void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target) void BKE_modifier_copydata_ex(struct ModifierData *md, struct ModifierData *target, const int flag); -bool BKE_modifier_depends_ontime(struct Scene *scene, - struct ModifierData *md, - int dag_eval_mode); +bool BKE_modifier_depends_ontime(struct Scene *scene, struct ModifierData *md, int dag_eval_mode); bool BKE_modifier_supports_mapping(struct ModifierData *md); bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md); bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index f0d50985237..351b73c320b 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6469,7 +6469,8 @@ void uiTemplateCacheFile(uiLayout *layout, const struct RenderEngineType *engine_type = CTX_data_engine_type(C); Scene *scene = CTX_data_scene(C); - const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, scene); + const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, + scene); if (!engine_supports_procedural) { row = uiLayoutRow(layout, false); diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index dfd3fdd80f8..fcf75040a9a 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -95,7 +95,9 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void walk(userData, ob, md, "texture"); } -static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *md, const int UNUSED(dag_eval_mode)) +static bool dependsOnTime(struct Scene *UNUSED(scene), + ModifierData *md, + const int UNUSED(dag_eval_mode)) { VolumeDisplaceModifierData *vdmd = reinterpret_cast(md); if (vdmd->texture) { -- cgit v1.2.3 From fca6b2780fa481a6e5673f9cafc94c8f995d2676 Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Thu, 19 Aug 2021 19:27:49 -0700 Subject: Cleanup: clang-format --- source/blender/blenkernel/intern/image_save.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index be86da05b57..f93ede517a9 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -409,7 +409,8 @@ bool BKE_image_save( BKE_reportf(reports, RPT_ERROR, "When saving a tiled image, the path '%s' must contain the UDIM tile number %d", - opts->filepath, first_tile->tile_number); + opts->filepath, + first_tile->tile_number); return false; } -- cgit v1.2.3 From 44b25b0ea5f415ea320cec1301dafa1523fb3ba4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 15:03:22 +1000 Subject: Cleanup: unused warnings --- source/blender/modifiers/intern/MOD_meshsequencecache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 2aa76c18c83..259c1cb2417 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -270,7 +270,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * return result ? result : mesh; #else - UNUSED_VARS(ctx, md); + UNUSED_VARS(ctx, md, generate_bounding_box_mesh); return mesh; #endif } @@ -283,7 +283,7 @@ static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mod return (mcmd->cache_file != NULL) && !BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode); #else - UNUSED_VARS(md); + UNUSED_VARS(scene, md, dag_eval_mode); return false; #endif } -- cgit v1.2.3 From ce3a6d7989387153911296e44ad00da3195f7299 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 15:08:27 +1000 Subject: Cleanup: rename BKE_mesh_free -> BKE_mesh_free_data It wasn't obvious this didn't free the memory of the mesh it's self leading to memory leaks. --- source/blender/blenkernel/BKE_mesh.h | 2 +- source/blender/blenkernel/intern/cloth.c | 4 ++-- source/blender/blenkernel/intern/mesh.c | 4 ++-- source/blender/editors/mesh/editmesh_knife_project.c | 2 +- source/blender/editors/mesh/editmesh_undo.c | 2 +- source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 8000e57e08e..5dab847182f 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -95,7 +95,7 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3]); -void BKE_mesh_free(struct Mesh *me); +void BKE_mesh_free_data(struct Mesh *me); void BKE_mesh_clear_geometry(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index f5ff936e18b..9aa2d017c48 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1574,7 +1574,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) BLI_edgeset_free(existing_vert_pairs); free_bvhtree_from_mesh(&treedata); if (tmp_mesh) { - BKE_mesh_free(tmp_mesh); + BKE_mesh_free_data(tmp_mesh); } return false; } @@ -1583,7 +1583,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) BLI_edgeset_free(existing_vert_pairs); free_bvhtree_from_mesh(&treedata); if (tmp_mesh) { - BKE_mesh_free(tmp_mesh); + BKE_mesh_free_data(tmp_mesh); } BLI_rng_free(rng); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 8257e54c618..c74c31e4c59 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -862,7 +862,7 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) } /** Free (or release) any data used by this mesh (does not free the mesh itself). */ -void BKE_mesh_free(Mesh *me) +void BKE_mesh_free_data(Mesh *me) { mesh_free_data(&me->id); } @@ -1078,7 +1078,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval) { /* Evaluated mesh may point to edit mesh, but never owns it. */ mesh_eval->edit_mesh = NULL; - BKE_mesh_free(mesh_eval); + BKE_mesh_free_data(mesh_eval); BKE_libblock_free_data(&mesh_eval->id, false); MEM_freeN(mesh_eval); } diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 16661897e87..2e63e397628 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -115,7 +115,7 @@ static LinkNode *knifeproject_poly_from_object(const bContext *C, BKE_nurbList_free(&nurbslist); if (me_eval_needs_free) { - BKE_mesh_free((struct Mesh *)me_eval); + BKE_mesh_free_data((struct Mesh *)me_eval); } } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index fc9e1aa8b1a..acf9e6c2d55 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -759,7 +759,7 @@ static void undomesh_free_data(UndoMesh *um) MEM_freeN(me->key); } - BKE_mesh_free(me); + BKE_mesh_free_data(me); } static Object *editmesh_object_from_context(bContext *C) diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index f02b73e8430..564a3c526f4 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1691,7 +1691,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu } if (obi->free_use_mesh) { - BKE_mesh_free(obi->original_me); + BKE_mesh_free_data(obi->original_me); MEM_freeN(obi->original_me); } -- cgit v1.2.3 From a48df97ada85960de4fd0eeba61b32e260bf378c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 15:19:58 +1000 Subject: Fix T90791: Knife project leaks memory with curve/text cutter --- source/blender/editors/mesh/editmesh_knife_project.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 2e63e397628..669a09b3fd3 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -33,6 +33,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" @@ -115,7 +116,7 @@ static LinkNode *knifeproject_poly_from_object(const bContext *C, BKE_nurbList_free(&nurbslist); if (me_eval_needs_free) { - BKE_mesh_free_data((struct Mesh *)me_eval); + BKE_id_free(NULL, (ID *)me_eval); } } -- cgit v1.2.3 From 9e2cd6b07784e58f0e9b2ad6800f3ca8b54f9745 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 15:57:50 +1000 Subject: Fix memory leak with building springs in the cloth simulator Error in 2788b0261cb7d33a2f6f2978ff4f55bb4987edae. --- source/blender/blenkernel/intern/cloth.c | 5 +++-- source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 9aa2d017c48..080a7c90c46 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -42,6 +42,7 @@ #include "BKE_cloth.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -1574,7 +1575,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) BLI_edgeset_free(existing_vert_pairs); free_bvhtree_from_mesh(&treedata); if (tmp_mesh) { - BKE_mesh_free_data(tmp_mesh); + BKE_id_free(NULL, &tmp_mesh->id); } return false; } @@ -1583,7 +1584,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) BLI_edgeset_free(existing_vert_pairs); free_bvhtree_from_mesh(&treedata); if (tmp_mesh) { - BKE_mesh_free_data(tmp_mesh); + BKE_id_free(NULL, &tmp_mesh->id); } BLI_rng_free(rng); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 564a3c526f4..e6b1012c981 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1649,6 +1649,7 @@ static int lineart_edge_type_duplication_count(char eflag) } static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb) { + printf("========================================================\nTESTING\n"); BMesh *bm; BMVert *v; BMFace *f; -- cgit v1.2.3 From 15a46a8b727a6475e14e503e93e7c135097d4eeb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 16:02:39 +1000 Subject: Cleanup: accidentally included printf --- source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index e6b1012c981..564a3c526f4 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1649,7 +1649,6 @@ static int lineart_edge_type_duplication_count(char eflag) } static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb) { - printf("========================================================\nTESTING\n"); BMesh *bm; BMVert *v; BMFace *f; -- cgit v1.2.3 From 40f0783d518a62c07f77394de12fb17a53024170 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 16:08:35 +1000 Subject: Cleanup: remove BKE_mesh_free_data use for lineart mesh copies Even though this didn't leak memory, BKE_mesh_free_data doesn't handle freeing data that is part of the ID making it error prone. --- source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 564a3c526f4..99e3d59a57f 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -41,6 +41,7 @@ #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" +#include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -1691,8 +1692,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu } if (obi->free_use_mesh) { - BKE_mesh_free_data(obi->original_me); - MEM_freeN(obi->original_me); + BKE_id_free(NULL, &obi->original_me); } if (rb->remove_doubles) { -- cgit v1.2.3 From e05db0c26bc407d146796a25acb8bf35506fb433 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 16:21:29 +1000 Subject: Cleanup: rename BKE_mesh_free_data -> BKE_mesh_free_data_for_undo This function only makes sense for undo which doesn't initialize the meshes ID. Otherwise BKE_id_free should be used. --- source/blender/blenkernel/BKE_mesh.h | 2 +- source/blender/blenkernel/intern/mesh.c | 9 ++++++--- source/blender/editors/mesh/editmesh_undo.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 5dab847182f..ae464a48e9e 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -95,7 +95,7 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3]); -void BKE_mesh_free_data(struct Mesh *me); +void BKE_mesh_free_data_for_undo(struct Mesh *me); void BKE_mesh_clear_geometry(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index c74c31e4c59..eb8e6aad736 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -861,8 +861,11 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL); } -/** Free (or release) any data used by this mesh (does not free the mesh itself). */ -void BKE_mesh_free_data(Mesh *me) +/** + * Free (or release) any data used by this mesh (does not free the mesh itself). + * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used. + */ +void BKE_mesh_free_data_for_undo(Mesh *me) { mesh_free_data(&me->id); } @@ -1078,7 +1081,7 @@ void BKE_mesh_eval_delete(struct Mesh *mesh_eval) { /* Evaluated mesh may point to edit mesh, but never owns it. */ mesh_eval->edit_mesh = NULL; - BKE_mesh_free_data(mesh_eval); + mesh_free_data(&mesh_eval->id); BKE_libblock_free_data(&mesh_eval->id, false); MEM_freeN(mesh_eval); } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index acf9e6c2d55..4d4e0a7d1b0 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -759,7 +759,7 @@ static void undomesh_free_data(UndoMesh *um) MEM_freeN(me->key); } - BKE_mesh_free_data(me); + BKE_mesh_free_data_for_undo(me); } static Object *editmesh_object_from_context(bContext *C) -- cgit v1.2.3 From cea24b4b4a2c76b632e5841ef6e458e11d82baa0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Aug 2021 16:35:35 +1000 Subject: Cleanup: use "free_data" suffix when the argument isn't freed Avoid API misuse that caused leaks in T90791 & 2788b0261cb7d33a2f6f2978ff4f55bb4987edae. --- source/blender/blenkernel/BKE_gpencil.h | 2 +- source/blender/blenkernel/BKE_image.h | 2 +- source/blender/blenkernel/BKE_key.h | 2 +- source/blender/blenkernel/BKE_screen.h | 2 +- source/blender/blenkernel/intern/gpencil.c | 6 +++--- source/blender/blenkernel/intern/image.c | 2 +- source/blender/blenkernel/intern/key.c | 2 +- source/blender/blenkernel/intern/screen.c | 2 +- source/blender/editors/gpencil/gpencil_undo.c | 2 +- source/blender/editors/mesh/editmesh_undo.c | 2 +- source/blender/editors/screen/screen_edit.c | 2 +- source/blender/editors/space_sequencer/space_sequencer.c | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 92e70b41e7b..b58317f4815 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -93,7 +93,7 @@ void BKE_gpencil_free_stroke(struct bGPDstroke *gps); bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); void BKE_gpencil_free_frames(struct bGPDlayer *gpl); void BKE_gpencil_free_layers(struct ListBase *list); -void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); +void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all); void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval); void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl); void BKE_gpencil_tag(struct bGPdata *gpd); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 3cab1a6b755..b62ad3ad24a 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -56,7 +56,7 @@ void BKE_image_free_buffers(struct Image *image); void BKE_image_free_buffers_ex(struct Image *image, bool do_lock); void BKE_image_free_gputextures(struct Image *ima); /* call from library */ -void BKE_image_free(struct Image *image); +void BKE_image_free_data(struct Image *image); typedef void(StampCallback)(void *data, const char *propname, char *propvalue, int len); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 70d65e02246..cb4fc607703 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -36,7 +36,7 @@ struct Object; extern "C" { #endif -void BKE_key_free(struct Key *key); +void BKE_key_free_data(struct Key *key); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct Main *bmain, struct ID *id); void BKE_key_sort(struct Key *key); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 0b08bbfeff5..6f341a12b82 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -473,7 +473,7 @@ void BKE_screen_view3d_shading_init(struct View3DShading *shading); /* screen */ void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area); -void BKE_screen_free(struct bScreen *screen); +void BKE_screen_free_data(struct bScreen *screen); void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL(); struct ScrEdge *BKE_screen_find_edge(const struct bScreen *screen, diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 9cdb7395925..9062fd2d39c 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -131,7 +131,7 @@ static void greasepencil_free_data(ID *id) { /* Really not ideal, but for now will do... In theory custom behaviors like not freeing cache * should be handled through specific API, and not be part of the generic one. */ - BKE_gpencil_free((bGPdata *)id, true); + BKE_gpencil_free_data((bGPdata *)id, true); } static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data) @@ -495,7 +495,7 @@ void BKE_gpencil_free_layers(ListBase *list) } /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ -void BKE_gpencil_free(bGPdata *gpd, bool free_all) +void BKE_gpencil_free_data(bGPdata *gpd, bool free_all) { /* free layers */ BKE_gpencil_free_layers(&gpd->layers); @@ -518,7 +518,7 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all) */ void BKE_gpencil_eval_delete(bGPdata *gpd_eval) { - BKE_gpencil_free(gpd_eval, true); + BKE_gpencil_free_data(gpd_eval, true); BKE_libblock_free_data(&gpd_eval->id, false); BLI_assert(!gpd_eval->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(gpd_eval); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 5701449a9e5..d87290e1eb4 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -534,7 +534,7 @@ void BKE_image_free_buffers(Image *ima) } /** Free (or release) any data used by this image (does not free the image itself). */ -void BKE_image_free(Image *ima) +void BKE_image_free_data(Image *ima) { image_free_data(&ima->id); } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index b59f51c36f7..f79058dcf21 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -245,7 +245,7 @@ typedef struct WeightsArrayCache { } WeightsArrayCache; /** Free (or release) any data used by this shapekey (does not free the key itself). */ -void BKE_key_free(Key *key) +void BKE_key_free_data(Key *key) { shapekey_free_data(&key->id); } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 1e725a6afc4..065240bddbc 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -728,7 +728,7 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map) } /** Free (or release) any data used by this screen (does not free the screen itself). */ -void BKE_screen_free(bScreen *screen) +void BKE_screen_free_data(bScreen *screen) { screen_free_data(&screen->id); } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 96e85cc6135..99b8b672327 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -125,7 +125,7 @@ static void gpencil_undo_free_node(bGPundonode *undo_node) */ undo_node->gpd->adt = NULL; - BKE_gpencil_free(undo_node->gpd, false); + BKE_gpencil_free_data(undo_node->gpd, false); MEM_freeN(undo_node->gpd); } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 4d4e0a7d1b0..f52cd94b8dc 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -755,7 +755,7 @@ static void undomesh_free_data(UndoMesh *um) #endif if (me->key) { - BKE_key_free(me->key); + BKE_key_free_data(me->key); MEM_freeN(me->key); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 506b5a9859d..1c068fdd6e4 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -230,7 +230,7 @@ bScreen *screen_add(Main *bmain, const char *name, const rcti *rect) void screen_data_copy(bScreen *to, bScreen *from) { /* free contents of 'to', is from blenkernel screen.c */ - BKE_screen_free(to); + BKE_screen_free_data(to); to->flag = from->flag; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 00f3bf6ac72..2a6e49edfb6 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -194,7 +194,7 @@ static void sequencer_free(SpaceLink *sl) SpaceSeq *sseq = (SpaceSeq *)sl; SequencerScopes *scopes = &sseq->scopes; - /* XXX if (sseq->gpd) BKE_gpencil_free(sseq->gpd); */ + /* XXX if (sseq->gpd) BKE_gpencil_free_data(sseq->gpd); */ if (scopes->zebra_ibuf) { IMB_freeImBuf(scopes->zebra_ibuf); -- cgit v1.2.3 From e95b197e987d3ed5d9efb6b228a7bdb56e1bd7bc Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Aug 2021 11:27:18 +0200 Subject: Cleanup: Add CLOG to wm_files_link.c --- .../blender/windowmanager/intern/wm_files_link.c | 51 ++++++++++------------ 1 file changed, 23 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index cdcb6c5163f..606c9252ff9 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -30,6 +30,8 @@ #include #include +#include "CLG_log.h" + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -76,6 +78,8 @@ #include "wm_files.h" +static CLG_LogRef LOG = {"wm.files_link"}; + /* -------------------------------------------------------------------- */ /** \name Link/Append Operator * \{ */ @@ -315,7 +319,7 @@ static bool wm_link_append_item_poll(ReportList *reports, short idcode; if (!group || !name) { - printf("skipping %s\n", path); + CLOG_WARN(&LOG, "Skipping %s", path); return false; } @@ -759,12 +763,12 @@ static void lib_relocate_do_remap(Main *bmain, BLI_assert(new_id); } if (new_id) { -#ifdef PRINT_DEBUG - printf("before remap of %s, old_id users: %d, new_id users: %d\n", - old_id->name, - old_id->us, - new_id->us); -#endif + CLOG_INFO(&LOG, + 4, + "Before remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); if (old_id->flag & LIB_FAKEUSER) { @@ -772,12 +776,12 @@ static void lib_relocate_do_remap(Main *bmain, id_fake_user_set(new_id); } -#ifdef PRINT_DEBUG - printf("after remap of %s, old_id users: %d, new_id users: %d\n", - old_id->name, - old_id->us, - new_id->us); -#endif + CLOG_INFO(&LOG, + 4, + "After remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); /* In some cases, new_id might become direct link, remove parent of library in this case. */ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { @@ -875,9 +879,7 @@ static void lib_relocate_do(bContext *C, item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); -#ifdef PRINT_DEBUG - printf("\tdatablock to seek for: %s\n", id->name); -#endif + CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); } } } @@ -1117,9 +1119,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } if (BLI_path_cmp(lib->filepath_abs, path) == 0) { -#ifdef PRINT_DEBUG - printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); -#endif + CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us); do_reload = true; @@ -1129,9 +1129,8 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) else { int totfiles = 0; -#ifdef PRINT_DEBUG - printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname); -#endif + CLOG_INFO( + &LOG, 4, "We are supposed to relocate '%s' lib to new '%s' one", lib->filepath, libname); /* Check if something is indicated for relocate. */ prop = RNA_struct_find_property(op->ptr, "files"); @@ -1157,17 +1156,13 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) continue; } -#ifdef PRINT_DEBUG - printf("\t candidate new lib to reload datablocks from: %s\n", path); -#endif + CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); wm_link_append_data_library_add(lapp_data, path); } RNA_END; } else { -#ifdef PRINT_DEBUG - printf("\t candidate new lib to reload datablocks from: %s\n", path); -#endif + CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); wm_link_append_data_library_add(lapp_data, path); } } -- cgit v1.2.3 From 2b6f0cc8367c04df8147cf231b11de4b4b8b41d5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 11:41:24 +0200 Subject: BLI: add utility methods to IndexMask --- source/blender/blenlib/BLI_index_mask.hh | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh index f04c0e9c80a..7a3169520ca 100644 --- a/source/blender/blenlib/BLI_index_mask.hh +++ b/source/blender/blenlib/BLI_index_mask.hh @@ -58,11 +58,7 @@ class IndexMask { */ IndexMask(Span indices) : indices_(indices) { -#ifdef DEBUG - for (int64_t i = 1; i < indices.size(); i++) { - BLI_assert(indices[i - 1] < indices[i]); - } -#endif + BLI_assert(IndexMask::indices_are_valid_index_mask(indices)); } /** @@ -94,6 +90,22 @@ class IndexMask { { } + /** Checks that the indices are non-negative and in ascending order. */ + static bool indices_are_valid_index_mask(Span indices) + { + if (!indices.is_empty()) { + if (indices.first() < 0) { + return false; + } + } + for (int64_t i = 1; i < indices.size(); i++) { + if (indices[i - 1] >= indices[i]) { + return false; + } + } + return true; + } + operator Span() const { return indices_; @@ -204,6 +216,11 @@ class IndexMask { { return indices_.size(); } + + bool is_empty() const + { + return indices_.is_empty(); + } }; } // namespace blender -- cgit v1.2.3 From fd51b05a02abcbdc9b551a9f2bf72a4ea6bc1f1c Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 11:42:31 +0200 Subject: Functions: add clear method to vector array --- source/blender/functions/FN_generic_vector_array.hh | 2 ++ source/blender/functions/intern/generic_vector_array.cc | 9 +++++++++ 2 files changed, 11 insertions(+) (limited to 'source/blender') diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index eeba0c9dba2..179e85671f8 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -82,6 +82,8 @@ class GVectorArray : NonCopyable, NonMovable { void extend(IndexMask mask, const GVVectorArray &values); void extend(IndexMask mask, const GVectorArray &values); + void clear(IndexMask mask); + GMutableSpan operator[](int64_t index); GSpan operator[](int64_t index) const; diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc index 9556d24218e..ec95a283919 100644 --- a/source/blender/functions/intern/generic_vector_array.cc +++ b/source/blender/functions/intern/generic_vector_array.cc @@ -78,6 +78,15 @@ void GVectorArray::extend(IndexMask mask, const GVectorArray &values) this->extend(mask, virtual_values); } +void GVectorArray::clear(IndexMask mask) +{ + for (const int64_t i : mask) { + Item &item = items_[i]; + type_.destruct_n(item.start, item.length); + item.length = 0; + } +} + GMutableSpan GVectorArray::operator[](const int64_t index) { Item &item = items_[index]; -- cgit v1.2.3 From d217b3421481161d33f27a30f6aec24e31c4ac61 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 11:43:54 +0200 Subject: Functions: add utility methods to parameter builder --- source/blender/functions/FN_multi_function_params.hh | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'source/blender') diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index e292d11def7..a480287d578 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -54,6 +54,11 @@ class MFParamsBuilder { MFParamsBuilder(const class MultiFunction &fn, int64_t min_array_size); + template void add_readonly_single_input_value(T value, StringRef expected_name = "") + { + T *value_ptr = &scope_.add_value(std::move(value), __func__); + this->add_readonly_single_input(value_ptr, expected_name); + } template void add_readonly_single_input(const T *value, StringRef expected_name = "") { this->add_readonly_single_input(scope_.construct( @@ -83,6 +88,12 @@ class MFParamsBuilder { this->add_readonly_vector_input( scope_.construct(__func__, vector_array), expected_name); } + void add_readonly_vector_input(const GSpan single_vector, StringRef expected_name = "") + { + this->add_readonly_vector_input( + scope_.construct(__func__, single_vector, min_array_size_), + expected_name); + } void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "") { this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name); -- cgit v1.2.3 From c1227fd4089f22edda3e137a7a1185fbb3daa968 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 12:05:03 +0200 Subject: Cleanup: remove duplicate line --- source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index e524564edab..4f70252ae75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -148,7 +148,5 @@ void register_node_type_geo_subdivision_surface() "NodeGeometrySubdivisionSurface", node_free_standard_storage, node_copy_standard_storage); - node_type_socket_templates( - &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); nodeRegisterType(&ntype); } -- cgit v1.2.3 From 7d8c71e8003ecb4d3a7fe2483a328d3f2d184faa Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 12:19:24 +0200 Subject: Geometry Nodes: add missing versioning for subdivision surface node This was missing from rBfecec1644ce54ea386eaeed5ca6748d4a7b2737b. --- source/blender/blenloader/intern/versioning_300.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index cac607ed152..eb01bfbfb9c 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -787,5 +787,23 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + /* Add node storage for subdivision surface node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == GEO_NODE_SUBDIVISION_SURFACE) { + if (node->storage == NULL) { + NodeGeometrySubdivisionSurface *data = MEM_callocN( + sizeof(NodeGeometrySubdivisionSurface), __func__); + data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; + data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL; + node->storage = data; + } + } + } + } + } + FOREACH_NODETREE_END; } } -- cgit v1.2.3 From 00812008129bdab48d328775b09332af12118867 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 20 Aug 2021 13:14:39 +0200 Subject: Functions: remove multi-function network The multi-function network system was able to compose multiple multi-functions into a new one and to evaluate that efficiently. This functionality was heavily used by the particle nodes prototype a year ago. However, since then we only used multi-functions without the need to compose them in geometry nodes. The upcoming "fields" in geometry nodes will need a way to compose multi-functions again. Unfortunately, the code removed in this commit was not ideal for this different kind of function composition. I've been working on an alternative that will be added separately when it becomes needed. I've had to update all the function nodes, because their interface depended on the multi-function network data structure a bit. The actual multi-function implementations are still the same though. --- source/blender/blenkernel/BKE_node.h | 15 +- source/blender/blenkernel/intern/simulation.cc | 4 - source/blender/functions/CMakeLists.txt | 7 - .../blender/functions/FN_generic_virtual_array.hh | 2 +- .../blender/functions/FN_multi_function_network.hh | 536 ---------- .../FN_multi_function_network_evaluation.hh | 62 -- .../FN_multi_function_network_optimization.hh | 29 - .../functions/FN_multi_function_signature.hh | 15 + .../functions/intern/multi_function_network.cc | 330 ------ .../intern/multi_function_network_evaluation.cc | 1083 -------------------- .../intern/multi_function_network_optimization.cc | 501 --------- .../tests/FN_multi_function_network_test.cc | 280 ----- .../functions/tests/FN_multi_function_test.cc | 92 +- .../tests/FN_multi_function_test_common.hh | 174 ++++ source/blender/modifiers/intern/MOD_nodes.cc | 5 +- .../modifiers/intern/MOD_nodes_evaluator.cc | 2 +- .../modifiers/intern/MOD_nodes_evaluator.hh | 6 +- source/blender/nodes/CMakeLists.txt | 6 +- source/blender/nodes/NOD_multi_function.hh | 130 +++ .../blender/nodes/NOD_node_tree_multi_function.hh | 390 ------- source/blender/nodes/NOD_type_callbacks.hh | 34 - .../blender/nodes/function/node_function_util.hh | 2 +- .../nodes/function/nodes/node_fn_boolean_math.cc | 19 +- .../nodes/function/nodes/node_fn_float_compare.cc | 25 +- .../nodes/function/nodes/node_fn_float_to_int.cc | 19 +- .../nodes/function/nodes/node_fn_input_string.cc | 12 +- .../nodes/function/nodes/node_fn_input_vector.cc | 10 +- .../nodes/function/nodes/node_fn_random_float.cc | 9 +- source/blender/nodes/intern/node_geometry_exec.cc | 1 - source/blender/nodes/intern/node_multi_function.cc | 40 + source/blender/nodes/intern/node_socket.cc | 1 - .../nodes/intern/node_tree_multi_function.cc | 409 -------- source/blender/nodes/intern/type_callbacks.cc | 60 -- source/blender/nodes/shader/node_shader_util.h | 2 +- .../nodes/shader/nodes/node_shader_clamp.cc | 6 +- .../nodes/shader/nodes/node_shader_curves.cc | 14 +- .../nodes/shader/nodes/node_shader_map_range.cc | 8 +- .../blender/nodes/shader/nodes/node_shader_math.cc | 67 +- .../nodes/shader/nodes/node_shader_mixRgb.cc | 6 +- .../nodes/shader/nodes/node_shader_sepcombRGB.cc | 8 +- .../nodes/shader/nodes/node_shader_sepcombXYZ.cc | 8 +- .../nodes/shader/nodes/node_shader_valToRgb.cc | 7 +- .../nodes/shader/nodes/node_shader_value.cc | 6 +- .../nodes/shader/nodes/node_shader_vector_math.cc | 28 +- .../shader/nodes/node_shader_vector_rotate.cc | 37 +- 45 files changed, 534 insertions(+), 3973 deletions(-) delete mode 100644 source/blender/functions/FN_multi_function_network.hh delete mode 100644 source/blender/functions/FN_multi_function_network_evaluation.hh delete mode 100644 source/blender/functions/FN_multi_function_network_optimization.hh delete mode 100644 source/blender/functions/intern/multi_function_network.cc delete mode 100644 source/blender/functions/intern/multi_function_network_evaluation.cc delete mode 100644 source/blender/functions/intern/multi_function_network_optimization.cc delete mode 100644 source/blender/functions/tests/FN_multi_function_network_test.cc create mode 100644 source/blender/functions/tests/FN_multi_function_test_common.hh create mode 100644 source/blender/nodes/NOD_multi_function.hh delete mode 100644 source/blender/nodes/NOD_node_tree_multi_function.hh delete mode 100644 source/blender/nodes/NOD_type_callbacks.hh create mode 100644 source/blender/nodes/intern/node_multi_function.cc delete mode 100644 source/blender/nodes/intern/node_tree_multi_function.cc delete mode 100644 source/blender/nodes/intern/type_callbacks.cc (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index caa7ab6de0a..c4393246926 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -111,8 +111,7 @@ typedef struct bNodeSocketTemplate { #ifdef __cplusplus namespace blender { namespace nodes { -class SocketMFNetworkBuilder; -class NodeMFNetworkBuilder; +class NodeMultiFunctionBuilder; class GeoNodeExecParams; } // namespace nodes namespace fn { @@ -121,18 +120,16 @@ class MFDataType; } // namespace fn } // namespace blender -using NodeExpandInMFNetworkFunction = void (*)(blender::nodes::NodeMFNetworkBuilder &builder); +using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); -using SocketExpandInMFNetworkFunction = void (*)(blender::nodes::SocketMFNetworkBuilder &builder); #else -typedef void *NodeExpandInMFNetworkFunction; -typedef void *SocketExpandInMFNetworkFunction; +typedef void *NodeMultiFunctionBuildFunction; typedef void *NodeGeometryExecFunction; typedef void *SocketGetCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPTypeFunction; @@ -196,8 +193,6 @@ typedef struct bNodeSocketType { /* Callback to free the socket type. */ void (*free_self)(struct bNodeSocketType *stype); - /* Expands the socket into a multi-function node that outputs the socket value. */ - SocketExpandInMFNetworkFunction expand_in_mf_network; /* Return the CPPType of this socket. */ SocketGetCPPTypeFunction get_base_cpp_type; /* Get the value of this socket in a generic way. */ @@ -332,8 +327,8 @@ typedef struct bNodeType { /* gpu */ NodeGPUExecFunction gpu_fn; - /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */ - NodeExpandInMFNetworkFunction expand_in_mf_network; + /* Build a multi-function for this node. */ + NodeMultiFunctionBuildFunction build_multi_function; /* Execute a geometry node. */ NodeGeometryExecFunction geometry_node_execute; diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 5aac29c19a7..4c97ccdf8b1 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -49,14 +49,10 @@ #include "BKE_simulation.h" #include "NOD_geometry.h" -#include "NOD_node_tree_multi_function.hh" #include "BLI_map.hh" #include "BLT_translation.h" -#include "FN_multi_function_network_evaluation.hh" -#include "FN_multi_function_network_optimization.hh" - #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 809294ad274..f8d2acc74a8 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -33,9 +33,6 @@ set(SRC intern/generic_virtual_vector_array.cc intern/multi_function.cc intern/multi_function_builder.cc - intern/multi_function_network.cc - intern/multi_function_network_evaluation.cc - intern/multi_function_network_optimization.cc FN_cpp_type.hh FN_cpp_type_make.hh @@ -49,9 +46,6 @@ set(SRC FN_multi_function_builder.hh FN_multi_function_context.hh FN_multi_function_data_type.hh - FN_multi_function_network.hh - FN_multi_function_network_evaluation.hh - FN_multi_function_network_optimization.hh FN_multi_function_param_type.hh FN_multi_function_params.hh FN_multi_function_signature.hh @@ -68,7 +62,6 @@ if(WITH_GTESTS) tests/FN_cpp_type_test.cc tests/FN_generic_span_test.cc tests/FN_generic_vector_array_test.cc - tests/FN_multi_function_network_test.cc tests/FN_multi_function_test.cc ) set(TEST_LIB diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index c9398ceb547..f429243e2de 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -129,7 +129,7 @@ class GVArray { } /* Same as `get_internal_single`, but `r_value` points to initialized memory. */ - void get_single_to_uninitialized(void *r_value) const + void get_internal_single_to_uninitialized(void *r_value) const { type_->default_construct(r_value); this->get_internal_single(r_value); diff --git a/source/blender/functions/FN_multi_function_network.hh b/source/blender/functions/FN_multi_function_network.hh deleted file mode 100644 index b303589106a..00000000000 --- a/source/blender/functions/FN_multi_function_network.hh +++ /dev/null @@ -1,536 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -/** \file - * \ingroup fn - * - * A multi-function network (`MFNetwork`) allows you to connect multiple multi-functions. The - * `MFNetworkEvaluator` is a multi-function that wraps an entire network into a new multi-function - * (which can be used in another network and so on). - * - * A MFNetwork is a graph data structure with two kinds of nodes: - * - MFFunctionNode: Represents a multi-function. Its input and output sockets correspond to - * parameters of the referenced multi-function. - * - MFDummyNode: Does not reference a multi-function. Instead it just has sockets that can be - * used to represent node group inputs and outputs. - * - * Links represent data flow. Unlinked input sockets have no value. In order to execute a function - * node, all its inputs have to be connected to something. - * - * Links are only allowed between sockets with the exact same MFDataType. There are no implicit - * conversions. - * - * Every input and output parameter of a multi-function corresponds to exactly one input or output - * socket respectively. A multiple parameter belongs to exactly one input AND one output socket. - * - * There is an .to_dot() method that generates a graph in dot format for debugging purposes. - */ - -#include "FN_multi_function.hh" - -#include "BLI_vector_set.hh" - -namespace blender::fn { - -class MFNode; -class MFFunctionNode; -class MFDummyNode; -class MFSocket; -class MFInputSocket; -class MFOutputSocket; -class MFNetwork; - -class MFNode : NonCopyable, NonMovable { - protected: - MFNetwork *network_; - Span inputs_; - Span outputs_; - bool is_dummy_; - int id_; - - friend MFNetwork; - - public: - StringRefNull name() const; - - int id() const; - - MFNetwork &network(); - const MFNetwork &network() const; - - bool is_dummy() const; - bool is_function() const; - - MFDummyNode &as_dummy(); - const MFDummyNode &as_dummy() const; - - MFFunctionNode &as_function(); - const MFFunctionNode &as_function() const; - - MFInputSocket &input(int index); - const MFInputSocket &input(int index) const; - - MFOutputSocket &output(int index); - const MFOutputSocket &output(int index) const; - - Span inputs(); - Span inputs() const; - - Span outputs(); - Span outputs() const; - - bool has_unlinked_inputs() const; - - private: - void destruct_sockets(); -}; - -class MFFunctionNode : public MFNode { - private: - const MultiFunction *function_; - Span input_param_indices_; - Span output_param_indices_; - - friend MFNetwork; - - public: - StringRefNull name() const; - - const MultiFunction &function() const; - - const MFInputSocket &input_for_param(int param_index) const; - const MFOutputSocket &output_for_param(int param_index) const; -}; - -class MFDummyNode : public MFNode { - protected: - StringRefNull name_; - MutableSpan input_names_; - MutableSpan output_names_; - - friend MFNetwork; - - public: - StringRefNull name() const; - - Span input_names() const; - Span output_names() const; -}; - -class MFSocket : NonCopyable, NonMovable { - protected: - MFNode *node_; - bool is_output_; - int index_; - MFDataType data_type_; - int id_; - StringRefNull name_; - - friend MFNetwork; - - public: - StringRefNull name() const; - - int id() const; - int index() const; - - const MFDataType &data_type() const; - - MFNode &node(); - const MFNode &node() const; - - bool is_input() const; - bool is_output() const; - - MFInputSocket &as_input(); - const MFInputSocket &as_input() const; - - MFOutputSocket &as_output(); - const MFOutputSocket &as_output() const; -}; - -class MFInputSocket : public MFSocket { - private: - MFOutputSocket *origin_; - - friend MFNetwork; - - public: - MFOutputSocket *origin(); - const MFOutputSocket *origin() const; -}; - -class MFOutputSocket : public MFSocket { - private: - Vector targets_; - - friend MFNetwork; - - public: - Span targets(); - Span targets() const; -}; - -class MFNetwork : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - - VectorSet function_nodes_; - VectorSet dummy_nodes_; - - Vector node_or_null_by_id_; - Vector socket_or_null_by_id_; - - public: - MFNetwork() = default; - ~MFNetwork(); - - MFFunctionNode &add_function(const MultiFunction &function); - MFDummyNode &add_dummy(StringRef name, - Span input_types, - Span output_types, - Span input_names, - Span output_names); - void add_link(MFOutputSocket &from, MFInputSocket &to); - - MFOutputSocket &add_input(StringRef name, MFDataType data_type); - MFInputSocket &add_output(StringRef name, MFDataType data_type); - - void relink(MFOutputSocket &old_output, MFOutputSocket &new_output); - - void remove(MFNode &node); - void remove(Span nodes); - - int socket_id_amount() const; - int node_id_amount() const; - - Span dummy_nodes(); - Span function_nodes(); - - MFNode *node_or_null_by_id(int id); - const MFNode *node_or_null_by_id(int id) const; - - MFSocket *socket_or_null_by_id(int id); - const MFSocket *socket_or_null_by_id(int id) const; - - void find_dependencies(Span sockets, - VectorSet &r_dummy_sockets, - VectorSet &r_unlinked_inputs) const; - - bool have_dummy_or_unlinked_dependencies(Span sockets) const; - - std::string to_dot(Span marked_nodes = {}) const; -}; - -/* -------------------------------------------------------------------- - * MFNode inline methods. - */ - -inline StringRefNull MFNode::name() const -{ - if (is_dummy_) { - return this->as_dummy().name(); - } - else { - return this->as_function().name(); - } -} - -inline int MFNode::id() const -{ - return id_; -} - -inline MFNetwork &MFNode::network() -{ - return *network_; -} - -inline const MFNetwork &MFNode::network() const -{ - return *network_; -} - -inline bool MFNode::is_dummy() const -{ - return is_dummy_; -} - -inline bool MFNode::is_function() const -{ - return !is_dummy_; -} - -inline MFDummyNode &MFNode::as_dummy() -{ - BLI_assert(is_dummy_); - return static_cast(*this); -} - -inline const MFDummyNode &MFNode::as_dummy() const -{ - BLI_assert(is_dummy_); - return static_cast(*this); -} - -inline MFFunctionNode &MFNode::as_function() -{ - BLI_assert(!is_dummy_); - return static_cast(*this); -} - -inline const MFFunctionNode &MFNode::as_function() const -{ - BLI_assert(!is_dummy_); - return static_cast(*this); -} - -inline MFInputSocket &MFNode::input(int index) -{ - return *inputs_[index]; -} - -inline const MFInputSocket &MFNode::input(int index) const -{ - return *inputs_[index]; -} - -inline MFOutputSocket &MFNode::output(int index) -{ - return *outputs_[index]; -} - -inline const MFOutputSocket &MFNode::output(int index) const -{ - return *outputs_[index]; -} - -inline Span MFNode::inputs() -{ - return inputs_; -} - -inline Span MFNode::inputs() const -{ - return inputs_; -} - -inline Span MFNode::outputs() -{ - return outputs_; -} - -inline Span MFNode::outputs() const -{ - return outputs_; -} - -inline bool MFNode::has_unlinked_inputs() const -{ - for (const MFInputSocket *socket : inputs_) { - if (socket->origin() == nullptr) { - return true; - } - } - return false; -} - -/* -------------------------------------------------------------------- - * MFFunctionNode inline methods. - */ - -inline StringRefNull MFFunctionNode::name() const -{ - return function_->name(); -} - -inline const MultiFunction &MFFunctionNode::function() const -{ - return *function_; -} - -inline const MFInputSocket &MFFunctionNode::input_for_param(int param_index) const -{ - return this->input(input_param_indices_.first_index(param_index)); -} - -inline const MFOutputSocket &MFFunctionNode::output_for_param(int param_index) const -{ - return this->output(output_param_indices_.first_index(param_index)); -} - -/* -------------------------------------------------------------------- - * MFDummyNode inline methods. - */ - -inline StringRefNull MFDummyNode::name() const -{ - return name_; -} - -inline Span MFDummyNode::input_names() const -{ - return input_names_; -} - -inline Span MFDummyNode::output_names() const -{ - return output_names_; -} - -/* -------------------------------------------------------------------- - * MFSocket inline methods. - */ - -inline StringRefNull MFSocket::name() const -{ - return name_; -} - -inline int MFSocket::id() const -{ - return id_; -} - -inline int MFSocket::index() const -{ - return index_; -} - -inline const MFDataType &MFSocket::data_type() const -{ - return data_type_; -} - -inline MFNode &MFSocket::node() -{ - return *node_; -} - -inline const MFNode &MFSocket::node() const -{ - return *node_; -} - -inline bool MFSocket::is_input() const -{ - return !is_output_; -} - -inline bool MFSocket::is_output() const -{ - return is_output_; -} - -inline MFInputSocket &MFSocket::as_input() -{ - BLI_assert(this->is_input()); - return static_cast(*this); -} - -inline const MFInputSocket &MFSocket::as_input() const -{ - BLI_assert(this->is_input()); - return static_cast(*this); -} - -inline MFOutputSocket &MFSocket::as_output() -{ - BLI_assert(this->is_output()); - return static_cast(*this); -} - -inline const MFOutputSocket &MFSocket::as_output() const -{ - BLI_assert(this->is_output()); - return static_cast(*this); -} - -/* -------------------------------------------------------------------- - * MFInputSocket inline methods. - */ - -inline MFOutputSocket *MFInputSocket::origin() -{ - return origin_; -} - -inline const MFOutputSocket *MFInputSocket::origin() const -{ - return origin_; -} - -/* -------------------------------------------------------------------- - * MFOutputSocket inline methods. - */ - -inline Span MFOutputSocket::targets() -{ - return targets_; -} - -inline Span MFOutputSocket::targets() const -{ - return targets_; -} - -/* -------------------------------------------------------------------- - * MFNetwork inline methods. - */ - -inline Span MFNetwork::dummy_nodes() -{ - return dummy_nodes_; -} - -inline Span MFNetwork::function_nodes() -{ - return function_nodes_; -} - -inline MFNode *MFNetwork::node_or_null_by_id(int id) -{ - return node_or_null_by_id_[id]; -} - -inline const MFNode *MFNetwork::node_or_null_by_id(int id) const -{ - return node_or_null_by_id_[id]; -} - -inline MFSocket *MFNetwork::socket_or_null_by_id(int id) -{ - return socket_or_null_by_id_[id]; -} - -inline const MFSocket *MFNetwork::socket_or_null_by_id(int id) const -{ - return socket_or_null_by_id_[id]; -} - -inline int MFNetwork::socket_id_amount() const -{ - return socket_or_null_by_id_.size(); -} - -inline int MFNetwork::node_id_amount() const -{ - return node_or_null_by_id_.size(); -} - -} // namespace blender::fn diff --git a/source/blender/functions/FN_multi_function_network_evaluation.hh b/source/blender/functions/FN_multi_function_network_evaluation.hh deleted file mode 100644 index 17cffa406f7..00000000000 --- a/source/blender/functions/FN_multi_function_network_evaluation.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -/** \file - * \ingroup fn - */ - -#include "FN_multi_function_network.hh" - -namespace blender::fn { - -class MFNetworkEvaluationStorage; - -class MFNetworkEvaluator : public MultiFunction { - private: - MFSignature signature_; - Vector inputs_; - Vector outputs_; - - public: - MFNetworkEvaluator(Vector inputs, Vector outputs); - - void call(IndexMask mask, MFParams params, MFContext context) const override; - - private: - using Storage = MFNetworkEvaluationStorage; - - void copy_inputs_to_storage(MFParams params, Storage &storage) const; - void copy_outputs_to_storage( - MFParams params, - Storage &storage, - Vector &outputs_to_initialize_in_the_end) const; - - void evaluate_network_to_compute_outputs(MFContext &global_context, Storage &storage) const; - - void evaluate_function(MFContext &global_context, - const MFFunctionNode &function_node, - Storage &storage) const; - - bool can_do_single_value_evaluation(const MFFunctionNode &function_node, Storage &storage) const; - - void initialize_remaining_outputs(MFParams params, - Storage &storage, - Span remaining_outputs) const; -}; - -} // namespace blender::fn diff --git a/source/blender/functions/FN_multi_function_network_optimization.hh b/source/blender/functions/FN_multi_function_network_optimization.hh deleted file mode 100644 index 96664fa368e..00000000000 --- a/source/blender/functions/FN_multi_function_network_optimization.hh +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include "FN_multi_function_network.hh" - -#include "BLI_resource_scope.hh" - -namespace blender::fn::mf_network_optimization { - -void dead_node_removal(MFNetwork &network); -void constant_folding(MFNetwork &network, ResourceScope &scope); -void common_subnetwork_elimination(MFNetwork &network); - -} // namespace blender::fn::mf_network_optimization diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index 23309c9a5e6..d05948cc645 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -160,6 +160,21 @@ class MFSignatureBuilder { } } + void add(StringRef name, const MFParamType ¶m_type) + { + switch (param_type.interface_type()) { + case MFParamType::Input: + this->input(name, param_type.data_type()); + break; + case MFParamType::Mutable: + this->mutable_(name, param_type.data_type()); + break; + case MFParamType::Output: + this->output(name, param_type.data_type()); + break; + } + } + /* Context */ /** This indicates that the function accesses the context. This disables optimizations that diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc deleted file mode 100644 index b5c2c09a35a..00000000000 --- a/source/blender/functions/intern/multi_function_network.cc +++ /dev/null @@ -1,330 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "BLI_dot_export.hh" -#include "BLI_stack.hh" - -#include "FN_multi_function_network.hh" - -namespace blender::fn { - -MFNetwork::~MFNetwork() -{ - for (MFFunctionNode *node : function_nodes_) { - node->destruct_sockets(); - node->~MFFunctionNode(); - } - for (MFDummyNode *node : dummy_nodes_) { - node->destruct_sockets(); - node->~MFDummyNode(); - } -} - -void MFNode::destruct_sockets() -{ - for (MFInputSocket *socket : inputs_) { - socket->~MFInputSocket(); - } - for (MFOutputSocket *socket : outputs_) { - socket->~MFOutputSocket(); - } -} - -/** - * Add a new function node to the network. The caller keeps the ownership of the function. The - * function should not be freed before the network. A reference to the new node is returned. The - * node is owned by the network. - */ -MFFunctionNode &MFNetwork::add_function(const MultiFunction &function) -{ - Vector input_param_indices, output_param_indices; - - for (int param_index : function.param_indices()) { - switch (function.param_type(param_index).interface_type()) { - case MFParamType::Input: { - input_param_indices.append(param_index); - break; - } - case MFParamType::Output: { - output_param_indices.append(param_index); - break; - } - case MFParamType::Mutable: { - input_param_indices.append(param_index); - output_param_indices.append(param_index); - break; - } - } - } - - MFFunctionNode &node = *allocator_.construct().release(); - function_nodes_.add_new(&node); - - node.network_ = this; - node.is_dummy_ = false; - node.id_ = node_or_null_by_id_.append_and_get_index(&node); - node.function_ = &function; - node.input_param_indices_ = allocator_.construct_array_copy(input_param_indices); - node.output_param_indices_ = allocator_.construct_array_copy(output_param_indices); - - node.inputs_ = allocator_.construct_elements_and_pointer_array( - input_param_indices.size()); - node.outputs_ = allocator_.construct_elements_and_pointer_array( - output_param_indices.size()); - - for (int i : input_param_indices.index_range()) { - int param_index = input_param_indices[i]; - MFParamType param = function.param_type(param_index); - BLI_assert(param.is_input_or_mutable()); - - MFInputSocket &socket = *node.inputs_[i]; - socket.data_type_ = param.data_type(); - socket.node_ = &node; - socket.index_ = i; - socket.is_output_ = false; - socket.name_ = function.param_name(param_index); - socket.origin_ = nullptr; - socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); - } - - for (int i : output_param_indices.index_range()) { - int param_index = output_param_indices[i]; - MFParamType param = function.param_type(param_index); - BLI_assert(param.is_output_or_mutable()); - - MFOutputSocket &socket = *node.outputs_[i]; - socket.data_type_ = param.data_type(); - socket.node_ = &node; - socket.index_ = i; - socket.is_output_ = true; - socket.name_ = function.param_name(param_index); - socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); - } - - return node; -} - -/** - * Add a dummy node with the given input and output sockets. - */ -MFDummyNode &MFNetwork::add_dummy(StringRef name, - Span input_types, - Span output_types, - Span input_names, - Span output_names) -{ - assert_same_size(input_types, input_names); - assert_same_size(output_types, output_names); - - MFDummyNode &node = *allocator_.construct().release(); - dummy_nodes_.add_new(&node); - - node.network_ = this; - node.is_dummy_ = true; - node.name_ = allocator_.copy_string(name); - node.id_ = node_or_null_by_id_.append_and_get_index(&node); - - node.inputs_ = allocator_.construct_elements_and_pointer_array( - input_types.size()); - node.outputs_ = allocator_.construct_elements_and_pointer_array( - output_types.size()); - - node.input_names_ = allocator_.allocate_array(input_types.size()); - node.output_names_ = allocator_.allocate_array(output_types.size()); - - for (int i : input_types.index_range()) { - MFInputSocket &socket = *node.inputs_[i]; - socket.data_type_ = input_types[i]; - socket.node_ = &node; - socket.index_ = i; - socket.is_output_ = false; - socket.name_ = allocator_.copy_string(input_names[i]); - socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); - node.input_names_[i] = socket.name_; - } - - for (int i : output_types.index_range()) { - MFOutputSocket &socket = *node.outputs_[i]; - socket.data_type_ = output_types[i]; - socket.node_ = &node; - socket.index_ = i; - socket.is_output_ = true; - socket.name_ = allocator_.copy_string(output_names[i]); - socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); - node.output_names_[i] = socket.name_; - } - - return node; -} - -/** - * Connect two sockets. This invokes undefined behavior if the sockets belong to different - * networks, the sockets have a different data type, or the `to` socket is connected to something - * else already. - */ -void MFNetwork::add_link(MFOutputSocket &from, MFInputSocket &to) -{ - BLI_assert(to.origin_ == nullptr); - BLI_assert(from.node_->network_ == to.node_->network_); - BLI_assert(from.data_type_ == to.data_type_); - from.targets_.append(&to); - to.origin_ = &from; -} - -MFOutputSocket &MFNetwork::add_input(StringRef name, MFDataType data_type) -{ - return this->add_dummy(name, {}, {data_type}, {}, {"Value"}).output(0); -} - -MFInputSocket &MFNetwork::add_output(StringRef name, MFDataType data_type) -{ - return this->add_dummy(name, {data_type}, {}, {"Value"}, {}).input(0); -} - -void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output) -{ - BLI_assert(&old_output != &new_output); - BLI_assert(old_output.data_type_ == new_output.data_type_); - for (MFInputSocket *input : old_output.targets()) { - input->origin_ = &new_output; - } - new_output.targets_.extend(old_output.targets_); - old_output.targets_.clear(); -} - -void MFNetwork::remove(MFNode &node) -{ - for (MFInputSocket *socket : node.inputs_) { - if (socket->origin_ != nullptr) { - socket->origin_->targets_.remove_first_occurrence_and_reorder(socket); - } - socket_or_null_by_id_[socket->id_] = nullptr; - } - for (MFOutputSocket *socket : node.outputs_) { - for (MFInputSocket *other : socket->targets_) { - other->origin_ = nullptr; - } - socket_or_null_by_id_[socket->id_] = nullptr; - } - node.destruct_sockets(); - if (node.is_dummy()) { - MFDummyNode &dummy_node = node.as_dummy(); - dummy_node.~MFDummyNode(); - dummy_nodes_.remove_contained(&dummy_node); - } - else { - MFFunctionNode &function_node = node.as_function(); - function_node.~MFFunctionNode(); - function_nodes_.remove_contained(&function_node); - } - node_or_null_by_id_[node.id_] = nullptr; -} - -void MFNetwork::remove(Span nodes) -{ - for (MFNode *node : nodes) { - this->remove(*node); - } -} - -void MFNetwork::find_dependencies(Span sockets, - VectorSet &r_dummy_sockets, - VectorSet &r_unlinked_inputs) const -{ - Set visited_nodes; - Stack sockets_to_check; - sockets_to_check.push_multiple(sockets); - - while (!sockets_to_check.is_empty()) { - const MFInputSocket &socket = *sockets_to_check.pop(); - const MFOutputSocket *origin_socket = socket.origin(); - if (origin_socket == nullptr) { - r_unlinked_inputs.add(&socket); - continue; - } - - const MFNode &origin_node = origin_socket->node(); - - if (origin_node.is_dummy()) { - r_dummy_sockets.add(origin_socket); - continue; - } - - if (visited_nodes.add(&origin_node)) { - sockets_to_check.push_multiple(origin_node.inputs()); - } - } -} - -bool MFNetwork::have_dummy_or_unlinked_dependencies(Span sockets) const -{ - VectorSet dummy_sockets; - VectorSet unlinked_inputs; - this->find_dependencies(sockets, dummy_sockets, unlinked_inputs); - return dummy_sockets.size() + unlinked_inputs.size() > 0; -} - -std::string MFNetwork::to_dot(Span marked_nodes) const -{ - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map dot_nodes; - - Vector all_nodes; - all_nodes.extend(function_nodes_.as_span().cast()); - all_nodes.extend(dummy_nodes_.as_span().cast()); - - for (const MFNode *node : all_nodes) { - dot::Node &dot_node = digraph.new_node(""); - - Vector input_names, output_names; - for (const MFInputSocket *socket : node->inputs_) { - input_names.append(socket->name() + "(" + socket->data_type().to_string() + ")"); - } - for (const MFOutputSocket *socket : node->outputs_) { - output_names.append(socket->name() + " (" + socket->data_type().to_string() + ")"); - } - - dot::NodeWithSocketsRef dot_node_ref{dot_node, node->name(), input_names, output_names}; - dot_nodes.add_new(node, dot_node_ref); - } - - for (const MFDummyNode *node : dummy_nodes_) { - dot_nodes.lookup(node).node().set_background_color("#77EE77"); - } - for (const MFNode *node : marked_nodes) { - dot_nodes.lookup(node).node().set_background_color("#7777EE"); - } - - for (const MFNode *to_node : all_nodes) { - dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node); - - for (const MFInputSocket *to_socket : to_node->inputs_) { - const MFOutputSocket *from_socket = to_socket->origin_; - if (from_socket != nullptr) { - const MFNode *from_node = from_socket->node_; - dot::NodeWithSocketsRef from_dot_node = dot_nodes.lookup(from_node); - digraph.new_edge(from_dot_node.output(from_socket->index_), - to_dot_node.input(to_socket->index_)); - } - } - } - - return digraph.to_dot_string(); -} - -} // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc deleted file mode 100644 index 9a0cb0c35ce..00000000000 --- a/source/blender/functions/intern/multi_function_network_evaluation.cc +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup fn - * - * The `MFNetworkEvaluator` class is a multi-function that consists of potentially many smaller - * multi-functions. When called, it traverses the underlying MFNetwork and executes the required - * function nodes. - * - * There are many possible approaches to evaluate a function network. The approach implemented - * below has the following features: - * - It does not use recursion. Those could become problematic with long node chains. - * - It can handle all existing parameter types (including mutable parameters). - * - Avoids data copies in many cases. - * - Every node is executed at most once. - * - Can compute sub-functions on a single element, when the result is the same for all elements. - * - * Possible improvements: - * - Cache and reuse buffers. - * - Use "deepest depth first" heuristic to decide which order the inputs of a node should be - * computed. This reduces the number of required temporary buffers when they are reused. - */ - -#include "FN_multi_function_network_evaluation.hh" - -#include "BLI_resource_scope.hh" -#include "BLI_stack.hh" - -namespace blender::fn { - -struct Value; - -/** - * This keeps track of all the values that flow through the multi-function network. Therefore it - * maintains a mapping between output sockets and their corresponding values. Every `value` - * references some memory, that is owned either by the caller or this storage. - * - * A value can be owned by different sockets over time to avoid unnecessary copies. - */ -class MFNetworkEvaluationStorage { - private: - LinearAllocator<> allocator_; - IndexMask mask_; - Array value_per_output_id_; - int64_t min_array_size_; - - public: - MFNetworkEvaluationStorage(IndexMask mask, int socket_id_amount); - ~MFNetworkEvaluationStorage(); - - /* Add the values that have been provided by the caller of the multi-function network. */ - void add_single_input_from_caller(const MFOutputSocket &socket, const GVArray &virtual_array); - void add_vector_input_from_caller(const MFOutputSocket &socket, - const GVVectorArray &virtual_vector_array); - void add_single_output_from_caller(const MFOutputSocket &socket, GMutableSpan span); - void add_vector_output_from_caller(const MFOutputSocket &socket, GVectorArray &vector_array); - - /* Get input buffers for function node evaluations. */ - const GVArray &get_single_input__full(const MFInputSocket &socket, ResourceScope &scope); - const GVArray &get_single_input__single(const MFInputSocket &socket, ResourceScope &scope); - const GVVectorArray &get_vector_input__full(const MFInputSocket &socket, ResourceScope &scope); - const GVVectorArray &get_vector_input__single(const MFInputSocket &socket, ResourceScope &scope); - - /* Get output buffers for function node evaluations. */ - GMutableSpan get_single_output__full(const MFOutputSocket &socket); - GMutableSpan get_single_output__single(const MFOutputSocket &socket); - GVectorArray &get_vector_output__full(const MFOutputSocket &socket); - GVectorArray &get_vector_output__single(const MFOutputSocket &socket); - - /* Get mutable buffers for function node evaluations. */ - GMutableSpan get_mutable_single__full(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope); - GMutableSpan get_mutable_single__single(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope); - GVectorArray &get_mutable_vector__full(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope); - GVectorArray &get_mutable_vector__single(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope); - - /* Mark a node as being done with evaluation. This might free temporary buffers that are no - * longer needed. */ - void finish_node(const MFFunctionNode &node); - void finish_output_socket(const MFOutputSocket &socket); - void finish_input_socket(const MFInputSocket &socket); - - IndexMask mask() const; - bool socket_is_computed(const MFOutputSocket &socket); - bool is_same_value_for_every_index(const MFOutputSocket &socket); - bool socket_has_buffer_for_output(const MFOutputSocket &socket); -}; - -MFNetworkEvaluator::MFNetworkEvaluator(Vector inputs, - Vector outputs) - : inputs_(std::move(inputs)), outputs_(std::move(outputs)) -{ - BLI_assert(outputs_.size() > 0); - MFSignatureBuilder signature{"Function Tree"}; - - for (const MFOutputSocket *socket : inputs_) { - BLI_assert(socket->node().is_dummy()); - - MFDataType type = socket->data_type(); - switch (type.category()) { - case MFDataType::Single: - signature.single_input(socket->name(), type.single_type()); - break; - case MFDataType::Vector: - signature.vector_input(socket->name(), type.vector_base_type()); - break; - } - } - - for (const MFInputSocket *socket : outputs_) { - BLI_assert(socket->node().is_dummy()); - - MFDataType type = socket->data_type(); - switch (type.category()) { - case MFDataType::Single: - signature.single_output(socket->name(), type.single_type()); - break; - case MFDataType::Vector: - signature.vector_output(socket->name(), type.vector_base_type()); - break; - } - } - - signature_ = signature.build(); - this->set_signature(&signature_); -} - -void MFNetworkEvaluator::call(IndexMask mask, MFParams params, MFContext context) const -{ - if (mask.size() == 0) { - return; - } - - const MFNetwork &network = outputs_[0]->node().network(); - Storage storage(mask, network.socket_id_amount()); - - Vector outputs_to_initialize_in_the_end; - - this->copy_inputs_to_storage(params, storage); - this->copy_outputs_to_storage(params, storage, outputs_to_initialize_in_the_end); - this->evaluate_network_to_compute_outputs(context, storage); - this->initialize_remaining_outputs(params, storage, outputs_to_initialize_in_the_end); -} - -BLI_NOINLINE void MFNetworkEvaluator::copy_inputs_to_storage(MFParams params, - Storage &storage) const -{ - for (int input_index : inputs_.index_range()) { - int param_index = input_index + 0; - const MFOutputSocket &socket = *inputs_[input_index]; - switch (socket.data_type().category()) { - case MFDataType::Single: { - const GVArray &input_list = params.readonly_single_input(param_index); - storage.add_single_input_from_caller(socket, input_list); - break; - } - case MFDataType::Vector: { - const GVVectorArray &input_list_list = params.readonly_vector_input(param_index); - storage.add_vector_input_from_caller(socket, input_list_list); - break; - } - } - } -} - -BLI_NOINLINE void MFNetworkEvaluator::copy_outputs_to_storage( - MFParams params, - Storage &storage, - Vector &outputs_to_initialize_in_the_end) const -{ - for (int output_index : outputs_.index_range()) { - int param_index = output_index + inputs_.size(); - const MFInputSocket &socket = *outputs_[output_index]; - const MFOutputSocket &origin = *socket.origin(); - - if (origin.node().is_dummy()) { - BLI_assert(inputs_.contains(&origin)); - /* Don't overwrite input buffers. */ - outputs_to_initialize_in_the_end.append(&socket); - continue; - } - - if (storage.socket_has_buffer_for_output(origin)) { - /* When two outputs will be initialized to the same values. */ - outputs_to_initialize_in_the_end.append(&socket); - continue; - } - - switch (socket.data_type().category()) { - case MFDataType::Single: { - GMutableSpan span = params.uninitialized_single_output(param_index); - storage.add_single_output_from_caller(origin, span); - break; - } - case MFDataType::Vector: { - GVectorArray &vector_array = params.vector_output(param_index); - storage.add_vector_output_from_caller(origin, vector_array); - break; - } - } - } -} - -BLI_NOINLINE void MFNetworkEvaluator::evaluate_network_to_compute_outputs( - MFContext &global_context, Storage &storage) const -{ - Stack sockets_to_compute; - for (const MFInputSocket *socket : outputs_) { - sockets_to_compute.push(socket->origin()); - } - - /* This is the main loop that traverses the MFNetwork. */ - while (!sockets_to_compute.is_empty()) { - const MFOutputSocket &socket = *sockets_to_compute.peek(); - const MFNode &node = socket.node(); - - if (storage.socket_is_computed(socket)) { - sockets_to_compute.pop(); - continue; - } - - BLI_assert(node.is_function()); - BLI_assert(!node.has_unlinked_inputs()); - const MFFunctionNode &function_node = node.as_function(); - - bool all_origins_are_computed = true; - for (const MFInputSocket *input_socket : function_node.inputs()) { - const MFOutputSocket *origin = input_socket->origin(); - if (origin != nullptr) { - if (!storage.socket_is_computed(*origin)) { - sockets_to_compute.push(origin); - all_origins_are_computed = false; - } - } - } - - if (all_origins_are_computed) { - this->evaluate_function(global_context, function_node, storage); - sockets_to_compute.pop(); - } - } -} - -BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_context, - const MFFunctionNode &function_node, - Storage &storage) const -{ - - const MultiFunction &function = function_node.function(); - // std::cout << "Function: " << function.name() << "\n"; - - if (this->can_do_single_value_evaluation(function_node, storage)) { - /* The function output would be the same for all elements. Therefore, it is enough to call the - * function only on a single element. This can avoid many duplicate computations. */ - MFParamsBuilder params{function, 1}; - ResourceScope &scope = params.resource_scope(); - - for (int param_index : function.param_indices()) { - MFParamType param_type = function.param_type(param_index); - switch (param_type.category()) { - case MFParamType::SingleInput: { - const MFInputSocket &socket = function_node.input_for_param(param_index); - const GVArray &values = storage.get_single_input__single(socket, scope); - params.add_readonly_single_input(values); - break; - } - case MFParamType::VectorInput: { - const MFInputSocket &socket = function_node.input_for_param(param_index); - const GVVectorArray &values = storage.get_vector_input__single(socket, scope); - params.add_readonly_vector_input(values); - break; - } - case MFParamType::SingleOutput: { - const MFOutputSocket &socket = function_node.output_for_param(param_index); - GMutableSpan values = storage.get_single_output__single(socket); - params.add_uninitialized_single_output(values); - break; - } - case MFParamType::VectorOutput: { - const MFOutputSocket &socket = function_node.output_for_param(param_index); - GVectorArray &values = storage.get_vector_output__single(socket); - params.add_vector_output(values); - break; - } - case MFParamType::SingleMutable: { - const MFInputSocket &input = function_node.input_for_param(param_index); - const MFOutputSocket &output = function_node.output_for_param(param_index); - GMutableSpan values = storage.get_mutable_single__single(input, output, scope); - params.add_single_mutable(values); - break; - } - case MFParamType::VectorMutable: { - const MFInputSocket &input = function_node.input_for_param(param_index); - const MFOutputSocket &output = function_node.output_for_param(param_index); - GVectorArray &values = storage.get_mutable_vector__single(input, output, scope); - params.add_vector_mutable(values); - break; - } - } - } - - function.call(IndexRange(1), params, global_context); - } - else { - MFParamsBuilder params{function, storage.mask().min_array_size()}; - ResourceScope &scope = params.resource_scope(); - - for (int param_index : function.param_indices()) { - MFParamType param_type = function.param_type(param_index); - switch (param_type.category()) { - case MFParamType::SingleInput: { - const MFInputSocket &socket = function_node.input_for_param(param_index); - const GVArray &values = storage.get_single_input__full(socket, scope); - params.add_readonly_single_input(values); - break; - } - case MFParamType::VectorInput: { - const MFInputSocket &socket = function_node.input_for_param(param_index); - const GVVectorArray &values = storage.get_vector_input__full(socket, scope); - params.add_readonly_vector_input(values); - break; - } - case MFParamType::SingleOutput: { - const MFOutputSocket &socket = function_node.output_for_param(param_index); - GMutableSpan values = storage.get_single_output__full(socket); - params.add_uninitialized_single_output(values); - break; - } - case MFParamType::VectorOutput: { - const MFOutputSocket &socket = function_node.output_for_param(param_index); - GVectorArray &values = storage.get_vector_output__full(socket); - params.add_vector_output(values); - break; - } - case MFParamType::SingleMutable: { - const MFInputSocket &input = function_node.input_for_param(param_index); - const MFOutputSocket &output = function_node.output_for_param(param_index); - GMutableSpan values = storage.get_mutable_single__full(input, output, scope); - params.add_single_mutable(values); - break; - } - case MFParamType::VectorMutable: { - const MFInputSocket &input = function_node.input_for_param(param_index); - const MFOutputSocket &output = function_node.output_for_param(param_index); - GVectorArray &values = storage.get_mutable_vector__full(input, output, scope); - params.add_vector_mutable(values); - break; - } - } - } - - function.call(storage.mask(), params, global_context); - } - - storage.finish_node(function_node); -} - -bool MFNetworkEvaluator::can_do_single_value_evaluation(const MFFunctionNode &function_node, - Storage &storage) const -{ - for (const MFInputSocket *socket : function_node.inputs()) { - if (!storage.is_same_value_for_every_index(*socket->origin())) { - return false; - } - } - if (storage.mask().min_array_size() >= 1) { - for (const MFOutputSocket *socket : function_node.outputs()) { - if (storage.socket_has_buffer_for_output(*socket)) { - return false; - } - } - } - return true; -} - -BLI_NOINLINE void MFNetworkEvaluator::initialize_remaining_outputs( - MFParams params, Storage &storage, Span remaining_outputs) const -{ - ResourceScope scope; - for (const MFInputSocket *socket : remaining_outputs) { - int param_index = inputs_.size() + outputs_.first_index_of(socket); - - switch (socket->data_type().category()) { - case MFDataType::Single: { - const GVArray &values = storage.get_single_input__full(*socket, scope); - GMutableSpan output_values = params.uninitialized_single_output(param_index); - values.materialize_to_uninitialized(storage.mask(), output_values.data()); - break; - } - case MFDataType::Vector: { - const GVVectorArray &values = storage.get_vector_input__full(*socket, scope); - GVectorArray &output_values = params.vector_output(param_index); - output_values.extend(storage.mask(), values); - break; - } - } - } -} - -/* -------------------------------------------------------------------- */ -/** \name Value Types - * \{ */ - -enum class ValueType { - InputSingle, - InputVector, - OutputSingle, - OutputVector, - OwnSingle, - OwnVector, -}; - -struct Value { - ValueType type; - - Value(ValueType type) : type(type) - { - } -}; - -struct InputSingleValue : public Value { - /** This virtual array has been provided by the code that called the multi-function network. */ - const GVArray &virtual_array; - - InputSingleValue(const GVArray &virtual_array) - : Value(ValueType::InputSingle), virtual_array(virtual_array) - { - } -}; - -struct InputVectorValue : public Value { - /** This virtual vector has been provided by the code that called the multi-function network. */ - const GVVectorArray &virtual_vector_array; - - InputVectorValue(const GVVectorArray &virtual_vector_array) - : Value(ValueType::InputVector), virtual_vector_array(virtual_vector_array) - { - } -}; - -struct OutputValue : public Value { - bool is_computed = false; - - OutputValue(ValueType type) : Value(type) - { - } -}; - -struct OutputSingleValue : public OutputValue { - /** This span has been provided by the code that called the multi-function network. */ - GMutableSpan span; - - OutputSingleValue(GMutableSpan span) : OutputValue(ValueType::OutputSingle), span(span) - { - } -}; - -struct OutputVectorValue : public OutputValue { - /** This vector array has been provided by the code that called the multi-function network. */ - GVectorArray *vector_array; - - OutputVectorValue(GVectorArray &vector_array) - : OutputValue(ValueType::OutputVector), vector_array(&vector_array) - { - } -}; - -struct OwnSingleValue : public Value { - /** This span has been allocated during the evaluation of the multi-function network and contains - * intermediate data. It has to be freed once the network evaluation is finished. */ - GMutableSpan span; - int max_remaining_users; - bool is_single_allocated; - - OwnSingleValue(GMutableSpan span, int max_remaining_users, bool is_single_allocated) - : Value(ValueType::OwnSingle), - span(span), - max_remaining_users(max_remaining_users), - is_single_allocated(is_single_allocated) - { - } -}; - -struct OwnVectorValue : public Value { - /** This vector array has been allocated during the evaluation of the multi-function network and - * contains intermediate data. It has to be freed once the network evaluation is finished. */ - GVectorArray *vector_array; - int max_remaining_users; - - OwnVectorValue(GVectorArray &vector_array, int max_remaining_users) - : Value(ValueType::OwnVector), - vector_array(&vector_array), - max_remaining_users(max_remaining_users) - { - } -}; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Storage methods - * \{ */ - -MFNetworkEvaluationStorage::MFNetworkEvaluationStorage(IndexMask mask, int socket_id_amount) - : mask_(mask), - value_per_output_id_(socket_id_amount, nullptr), - min_array_size_(mask.min_array_size()) -{ -} - -MFNetworkEvaluationStorage::~MFNetworkEvaluationStorage() -{ - for (Value *any_value : value_per_output_id_) { - if (any_value == nullptr) { - continue; - } - if (any_value->type == ValueType::OwnSingle) { - OwnSingleValue *value = static_cast(any_value); - GMutableSpan span = value->span; - const CPPType &type = span.type(); - if (value->is_single_allocated) { - type.destruct(span.data()); - } - else { - type.destruct_indices(span.data(), mask_); - MEM_freeN(span.data()); - } - } - else if (any_value->type == ValueType::OwnVector) { - OwnVectorValue *value = static_cast(any_value); - delete value->vector_array; - } - } -} - -IndexMask MFNetworkEvaluationStorage::mask() const -{ - return mask_; -} - -bool MFNetworkEvaluationStorage::socket_is_computed(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - return false; - } - if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) { - return static_cast(any_value)->is_computed; - } - return true; -} - -bool MFNetworkEvaluationStorage::is_same_value_for_every_index(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - switch (any_value->type) { - case ValueType::OwnSingle: - return static_cast(any_value)->span.size() == 1; - case ValueType::OwnVector: - return static_cast(any_value)->vector_array->size() == 1; - case ValueType::InputSingle: - return static_cast(any_value)->virtual_array.is_single(); - case ValueType::InputVector: - return static_cast(any_value)->virtual_vector_array.is_single_vector(); - case ValueType::OutputSingle: - return static_cast(any_value)->span.size() == 1; - case ValueType::OutputVector: - return static_cast(any_value)->vector_array->size() == 1; - } - BLI_assert(false); - return false; -} - -bool MFNetworkEvaluationStorage::socket_has_buffer_for_output(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - return false; - } - - BLI_assert(ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)); - return true; -} - -void MFNetworkEvaluationStorage::finish_node(const MFFunctionNode &node) -{ - for (const MFInputSocket *socket : node.inputs()) { - this->finish_input_socket(*socket); - } - for (const MFOutputSocket *socket : node.outputs()) { - this->finish_output_socket(*socket); - } -} - -void MFNetworkEvaluationStorage::finish_output_socket(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - return; - } - - if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) { - static_cast(any_value)->is_computed = true; - } -} - -void MFNetworkEvaluationStorage::finish_input_socket(const MFInputSocket &socket) -{ - const MFOutputSocket &origin = *socket.origin(); - - Value *any_value = value_per_output_id_[origin.id()]; - if (any_value == nullptr) { - /* Can happen when a value has been forward to the next node. */ - return; - } - - switch (any_value->type) { - case ValueType::InputSingle: - case ValueType::OutputSingle: - case ValueType::InputVector: - case ValueType::OutputVector: { - break; - } - case ValueType::OwnSingle: { - OwnSingleValue *value = static_cast(any_value); - BLI_assert(value->max_remaining_users >= 1); - value->max_remaining_users--; - if (value->max_remaining_users == 0) { - GMutableSpan span = value->span; - const CPPType &type = span.type(); - if (value->is_single_allocated) { - type.destruct(span.data()); - } - else { - type.destruct_indices(span.data(), mask_); - MEM_freeN(span.data()); - } - value_per_output_id_[origin.id()] = nullptr; - } - break; - } - case ValueType::OwnVector: { - OwnVectorValue *value = static_cast(any_value); - BLI_assert(value->max_remaining_users >= 1); - value->max_remaining_users--; - if (value->max_remaining_users == 0) { - delete value->vector_array; - value_per_output_id_[origin.id()] = nullptr; - } - break; - } - } -} - -void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSocket &socket, - const GVArray &virtual_array) -{ - BLI_assert(value_per_output_id_[socket.id()] == nullptr); - BLI_assert(virtual_array.size() >= min_array_size_); - - auto *value = allocator_.construct(virtual_array).release(); - value_per_output_id_[socket.id()] = value; -} - -void MFNetworkEvaluationStorage::add_vector_input_from_caller( - const MFOutputSocket &socket, const GVVectorArray &virtual_vector_array) -{ - BLI_assert(value_per_output_id_[socket.id()] == nullptr); - BLI_assert(virtual_vector_array.size() >= min_array_size_); - - auto *value = allocator_.construct(virtual_vector_array).release(); - value_per_output_id_[socket.id()] = value; -} - -void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSocket &socket, - GMutableSpan span) -{ - BLI_assert(value_per_output_id_[socket.id()] == nullptr); - BLI_assert(span.size() >= min_array_size_); - - auto *value = allocator_.construct(span).release(); - value_per_output_id_[socket.id()] = value; -} - -void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSocket &socket, - GVectorArray &vector_array) -{ - BLI_assert(value_per_output_id_[socket.id()] == nullptr); - BLI_assert(vector_array.size() >= min_array_size_); - - auto *value = allocator_.construct(vector_array).release(); - value_per_output_id_[socket.id()] = value; -} - -GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - const CPPType &type = socket.data_type().single_type(); - void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT); - GMutableSpan span(type, buffer, min_array_size_); - - auto *value = - allocator_.construct(span, socket.targets().size(), false).release(); - value_per_output_id_[socket.id()] = value; - - return span; - } - - BLI_assert(any_value->type == ValueType::OutputSingle); - return static_cast(any_value)->span; -} - -GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - const CPPType &type = socket.data_type().single_type(); - void *buffer = allocator_.allocate(type.size(), type.alignment()); - GMutableSpan span(type, buffer, 1); - - auto *value = - allocator_.construct(span, socket.targets().size(), true).release(); - value_per_output_id_[socket.id()] = value; - - return value->span; - } - - BLI_assert(any_value->type == ValueType::OutputSingle); - GMutableSpan span = static_cast(any_value)->span; - BLI_assert(span.size() == 1); - return span; -} - -GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - const CPPType &type = socket.data_type().vector_base_type(); - GVectorArray *vector_array = new GVectorArray(type, min_array_size_); - - auto *value = - allocator_.construct(*vector_array, socket.targets().size()).release(); - value_per_output_id_[socket.id()] = value; - - return *value->vector_array; - } - - BLI_assert(any_value->type == ValueType::OutputVector); - return *static_cast(any_value)->vector_array; -} - -GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutputSocket &socket) -{ - Value *any_value = value_per_output_id_[socket.id()]; - if (any_value == nullptr) { - const CPPType &type = socket.data_type().vector_base_type(); - GVectorArray *vector_array = new GVectorArray(type, 1); - - auto *value = - allocator_.construct(*vector_array, socket.targets().size()).release(); - value_per_output_id_[socket.id()] = value; - - return *value->vector_array; - } - - BLI_assert(any_value->type == ValueType::OutputVector); - GVectorArray &vector_array = *static_cast(any_value)->vector_array; - BLI_assert(vector_array.size() == 1); - return vector_array; -} - -GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope) -{ - const MFOutputSocket &from = *input.origin(); - const MFOutputSocket &to = output; - const CPPType &type = from.data_type().single_type(); - - Value *from_any_value = value_per_output_id_[from.id()]; - Value *to_any_value = value_per_output_id_[to.id()]; - BLI_assert(from_any_value != nullptr); - BLI_assert(type == to.data_type().single_type()); - - if (to_any_value != nullptr) { - BLI_assert(to_any_value->type == ValueType::OutputSingle); - GMutableSpan span = static_cast(to_any_value)->span; - const GVArray &virtual_array = this->get_single_input__full(input, scope); - virtual_array.materialize_to_uninitialized(mask_, span.data()); - return span; - } - - if (from_any_value->type == ValueType::OwnSingle) { - OwnSingleValue *value = static_cast(from_any_value); - if (value->max_remaining_users == 1 && !value->is_single_allocated) { - value_per_output_id_[to.id()] = value; - value_per_output_id_[from.id()] = nullptr; - value->max_remaining_users = to.targets().size(); - return value->span; - } - } - - const GVArray &virtual_array = this->get_single_input__full(input, scope); - void *new_buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT); - GMutableSpan new_array_ref(type, new_buffer, min_array_size_); - virtual_array.materialize_to_uninitialized(mask_, new_array_ref.data()); - - OwnSingleValue *new_value = - allocator_.construct(new_array_ref, to.targets().size(), false).release(); - value_per_output_id_[to.id()] = new_value; - return new_array_ref; -} - -GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope) -{ - const MFOutputSocket &from = *input.origin(); - const MFOutputSocket &to = output; - const CPPType &type = from.data_type().single_type(); - - Value *from_any_value = value_per_output_id_[from.id()]; - Value *to_any_value = value_per_output_id_[to.id()]; - BLI_assert(from_any_value != nullptr); - BLI_assert(type == to.data_type().single_type()); - - if (to_any_value != nullptr) { - BLI_assert(to_any_value->type == ValueType::OutputSingle); - GMutableSpan span = static_cast(to_any_value)->span; - BLI_assert(span.size() == 1); - const GVArray &virtual_array = this->get_single_input__single(input, scope); - virtual_array.get_single_to_uninitialized(span[0]); - return span; - } - - if (from_any_value->type == ValueType::OwnSingle) { - OwnSingleValue *value = static_cast(from_any_value); - if (value->max_remaining_users == 1) { - value_per_output_id_[to.id()] = value; - value_per_output_id_[from.id()] = nullptr; - value->max_remaining_users = to.targets().size(); - BLI_assert(value->span.size() == 1); - return value->span; - } - } - - const GVArray &virtual_array = this->get_single_input__single(input, scope); - - void *new_buffer = allocator_.allocate(type.size(), type.alignment()); - virtual_array.get_single_to_uninitialized(new_buffer); - GMutableSpan new_array_ref(type, new_buffer, 1); - - OwnSingleValue *new_value = - allocator_.construct(new_array_ref, to.targets().size(), true).release(); - value_per_output_id_[to.id()] = new_value; - return new_array_ref; -} - -GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope) -{ - const MFOutputSocket &from = *input.origin(); - const MFOutputSocket &to = output; - const CPPType &base_type = from.data_type().vector_base_type(); - - Value *from_any_value = value_per_output_id_[from.id()]; - Value *to_any_value = value_per_output_id_[to.id()]; - BLI_assert(from_any_value != nullptr); - BLI_assert(base_type == to.data_type().vector_base_type()); - - if (to_any_value != nullptr) { - BLI_assert(to_any_value->type == ValueType::OutputVector); - GVectorArray &vector_array = *static_cast(to_any_value)->vector_array; - const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, scope); - vector_array.extend(mask_, virtual_vector_array); - return vector_array; - } - - if (from_any_value->type == ValueType::OwnVector) { - OwnVectorValue *value = static_cast(from_any_value); - if (value->max_remaining_users == 1) { - value_per_output_id_[to.id()] = value; - value_per_output_id_[from.id()] = nullptr; - value->max_remaining_users = to.targets().size(); - return *value->vector_array; - } - } - - const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, scope); - - GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_); - new_vector_array->extend(mask_, virtual_vector_array); - - OwnVectorValue *new_value = - allocator_.construct(*new_vector_array, to.targets().size()).release(); - value_per_output_id_[to.id()] = new_value; - - return *new_vector_array; -} - -GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInputSocket &input, - const MFOutputSocket &output, - ResourceScope &scope) -{ - const MFOutputSocket &from = *input.origin(); - const MFOutputSocket &to = output; - const CPPType &base_type = from.data_type().vector_base_type(); - - Value *from_any_value = value_per_output_id_[from.id()]; - Value *to_any_value = value_per_output_id_[to.id()]; - BLI_assert(from_any_value != nullptr); - BLI_assert(base_type == to.data_type().vector_base_type()); - - if (to_any_value != nullptr) { - BLI_assert(to_any_value->type == ValueType::OutputVector); - GVectorArray &vector_array = *static_cast(to_any_value)->vector_array; - BLI_assert(vector_array.size() == 1); - const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, scope); - vector_array.extend({0}, virtual_vector_array); - return vector_array; - } - - if (from_any_value->type == ValueType::OwnVector) { - OwnVectorValue *value = static_cast(from_any_value); - if (value->max_remaining_users == 1) { - value_per_output_id_[to.id()] = value; - value_per_output_id_[from.id()] = nullptr; - value->max_remaining_users = to.targets().size(); - return *value->vector_array; - } - } - - const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, scope); - - GVectorArray *new_vector_array = new GVectorArray(base_type, 1); - new_vector_array->extend({0}, virtual_vector_array); - - OwnVectorValue *new_value = - allocator_.construct(*new_vector_array, to.targets().size()).release(); - value_per_output_id_[to.id()] = new_value; - return *new_vector_array; -} - -const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &socket, - ResourceScope &scope) -{ - const MFOutputSocket &origin = *socket.origin(); - Value *any_value = value_per_output_id_[origin.id()]; - BLI_assert(any_value != nullptr); - - if (any_value->type == ValueType::OwnSingle) { - OwnSingleValue *value = static_cast(any_value); - if (value->is_single_allocated) { - return scope.construct( - __func__, value->span.type(), min_array_size_, value->span.data()); - } - - return scope.construct(__func__, value->span); - } - if (any_value->type == ValueType::InputSingle) { - InputSingleValue *value = static_cast(any_value); - return value->virtual_array; - } - if (any_value->type == ValueType::OutputSingle) { - OutputSingleValue *value = static_cast(any_value); - BLI_assert(value->is_computed); - return scope.construct(__func__, value->span); - } - - BLI_assert(false); - return scope.construct(__func__, CPPType::get()); -} - -const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket, - ResourceScope &scope) -{ - const MFOutputSocket &origin = *socket.origin(); - Value *any_value = value_per_output_id_[origin.id()]; - BLI_assert(any_value != nullptr); - - if (any_value->type == ValueType::OwnSingle) { - OwnSingleValue *value = static_cast(any_value); - BLI_assert(value->span.size() == 1); - return scope.construct(__func__, value->span); - } - if (any_value->type == ValueType::InputSingle) { - InputSingleValue *value = static_cast(any_value); - BLI_assert(value->virtual_array.is_single()); - return value->virtual_array; - } - if (any_value->type == ValueType::OutputSingle) { - OutputSingleValue *value = static_cast(any_value); - BLI_assert(value->is_computed); - BLI_assert(value->span.size() == 1); - return scope.construct(__func__, value->span); - } - - BLI_assert(false); - return scope.construct(__func__, CPPType::get()); -} - -const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full( - const MFInputSocket &socket, ResourceScope &scope) -{ - const MFOutputSocket &origin = *socket.origin(); - Value *any_value = value_per_output_id_[origin.id()]; - BLI_assert(any_value != nullptr); - - if (any_value->type == ValueType::OwnVector) { - OwnVectorValue *value = static_cast(any_value); - if (value->vector_array->size() == 1) { - GSpan span = (*value->vector_array)[0]; - return scope.construct(__func__, span, min_array_size_); - } - - return scope.construct(__func__, *value->vector_array); - } - if (any_value->type == ValueType::InputVector) { - InputVectorValue *value = static_cast(any_value); - return value->virtual_vector_array; - } - if (any_value->type == ValueType::OutputVector) { - OutputVectorValue *value = static_cast(any_value); - return scope.construct(__func__, *value->vector_array); - } - - BLI_assert(false); - return scope.construct(__func__, GSpan(CPPType::get()), 0); -} - -const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single( - const MFInputSocket &socket, ResourceScope &scope) -{ - const MFOutputSocket &origin = *socket.origin(); - Value *any_value = value_per_output_id_[origin.id()]; - BLI_assert(any_value != nullptr); - - if (any_value->type == ValueType::OwnVector) { - OwnVectorValue *value = static_cast(any_value); - BLI_assert(value->vector_array->size() == 1); - return scope.construct(__func__, *value->vector_array); - } - if (any_value->type == ValueType::InputVector) { - InputVectorValue *value = static_cast(any_value); - BLI_assert(value->virtual_vector_array.is_single_vector()); - return value->virtual_vector_array; - } - if (any_value->type == ValueType::OutputVector) { - OutputVectorValue *value = static_cast(any_value); - BLI_assert(value->vector_array->size() == 1); - return scope.construct(__func__, *value->vector_array); - } - - BLI_assert(false); - return scope.construct(__func__, GSpan(CPPType::get()), 0); -} - -/** \} */ - -} // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_network_optimization.cc b/source/blender/functions/intern/multi_function_network_optimization.cc deleted file mode 100644 index 75c3583c5e5..00000000000 --- a/source/blender/functions/intern/multi_function_network_optimization.cc +++ /dev/null @@ -1,501 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup fn - */ - -/* Used to check if two multi-functions have the exact same type. */ -#include - -#include "FN_multi_function_builder.hh" -#include "FN_multi_function_network_evaluation.hh" -#include "FN_multi_function_network_optimization.hh" - -#include "BLI_disjoint_set.hh" -#include "BLI_ghash.h" -#include "BLI_map.hh" -#include "BLI_multi_value_map.hh" -#include "BLI_rand.h" -#include "BLI_stack.hh" - -namespace blender::fn::mf_network_optimization { - -/* -------------------------------------------------------------------- */ -/** \name Utility functions to find nodes in a network. - * \{ */ - -static bool set_tag_and_check_if_modified(bool &tag, bool new_value) -{ - if (tag != new_value) { - tag = new_value; - return true; - } - - return false; -} - -static Array mask_nodes_to_the_left(MFNetwork &network, Span nodes) -{ - Array is_to_the_left(network.node_id_amount(), false); - Stack nodes_to_check; - - for (MFNode *node : nodes) { - is_to_the_left[node->id()] = true; - nodes_to_check.push(node); - } - - while (!nodes_to_check.is_empty()) { - MFNode &node = *nodes_to_check.pop(); - - for (MFInputSocket *input_socket : node.inputs()) { - MFOutputSocket *origin = input_socket->origin(); - if (origin != nullptr) { - MFNode &origin_node = origin->node(); - if (set_tag_and_check_if_modified(is_to_the_left[origin_node.id()], true)) { - nodes_to_check.push(&origin_node); - } - } - } - } - - return is_to_the_left; -} - -static Array mask_nodes_to_the_right(MFNetwork &network, Span nodes) -{ - Array is_to_the_right(network.node_id_amount(), false); - Stack nodes_to_check; - - for (MFNode *node : nodes) { - is_to_the_right[node->id()] = true; - nodes_to_check.push(node); - } - - while (!nodes_to_check.is_empty()) { - MFNode &node = *nodes_to_check.pop(); - - for (MFOutputSocket *output_socket : node.outputs()) { - for (MFInputSocket *target_socket : output_socket->targets()) { - MFNode &target_node = target_socket->node(); - if (set_tag_and_check_if_modified(is_to_the_right[target_node.id()], true)) { - nodes_to_check.push(&target_node); - } - } - } - } - - return is_to_the_right; -} - -static Vector find_nodes_based_on_mask(MFNetwork &network, - Span id_mask, - bool mask_value) -{ - Vector nodes; - for (int id : id_mask.index_range()) { - if (id_mask[id] == mask_value) { - MFNode *node = network.node_or_null_by_id(id); - if (node != nullptr) { - nodes.append(node); - } - } - } - return nodes; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Dead Node Removal - * \{ */ - -/** - * Unused nodes are all those nodes that no dummy node depends upon. - */ -void dead_node_removal(MFNetwork &network) -{ - Array node_is_used_mask = mask_nodes_to_the_left(network, - network.dummy_nodes().cast()); - Vector nodes_to_remove = find_nodes_based_on_mask(network, node_is_used_mask, false); - network.remove(nodes_to_remove); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Constant Folding - * \{ */ - -static bool function_node_can_be_constant(MFFunctionNode *node) -{ - if (node->has_unlinked_inputs()) { - return false; - } - if (node->function().depends_on_context()) { - return false; - } - return true; -} - -static Vector find_non_constant_nodes(MFNetwork &network) -{ - Vector non_constant_nodes; - non_constant_nodes.extend(network.dummy_nodes().cast()); - - for (MFFunctionNode *node : network.function_nodes()) { - if (!function_node_can_be_constant(node)) { - non_constant_nodes.append(node); - } - } - return non_constant_nodes; -} - -static bool output_has_non_constant_target_node(MFOutputSocket *output_socket, - Span is_not_constant_mask) -{ - for (MFInputSocket *target_socket : output_socket->targets()) { - MFNode &target_node = target_socket->node(); - bool target_is_not_constant = is_not_constant_mask[target_node.id()]; - if (target_is_not_constant) { - return true; - } - } - return false; -} - -static MFInputSocket *try_find_dummy_target_socket(MFOutputSocket *output_socket) -{ - for (MFInputSocket *target_socket : output_socket->targets()) { - if (target_socket->node().is_dummy()) { - return target_socket; - } - } - return nullptr; -} - -static Vector find_constant_inputs_to_fold( - MFNetwork &network, Vector &r_temporary_nodes) -{ - Vector non_constant_nodes = find_non_constant_nodes(network); - Array is_not_constant_mask = mask_nodes_to_the_right(network, non_constant_nodes); - Vector constant_nodes = find_nodes_based_on_mask(network, is_not_constant_mask, false); - - Vector sockets_to_compute; - for (MFNode *node : constant_nodes) { - if (node->inputs().size() == 0) { - continue; - } - - for (MFOutputSocket *output_socket : node->outputs()) { - MFDataType data_type = output_socket->data_type(); - if (output_has_non_constant_target_node(output_socket, is_not_constant_mask)) { - MFInputSocket *dummy_target = try_find_dummy_target_socket(output_socket); - if (dummy_target == nullptr) { - dummy_target = &network.add_output("Dummy", data_type); - network.add_link(*output_socket, *dummy_target); - r_temporary_nodes.append(&dummy_target->node().as_dummy()); - } - - sockets_to_compute.append(dummy_target); - } - } - } - return sockets_to_compute; -} - -static void prepare_params_for_constant_folding(const MultiFunction &network_fn, - MFParamsBuilder ¶ms, - ResourceScope &scope) -{ - for (int param_index : network_fn.param_indices()) { - MFParamType param_type = network_fn.param_type(param_index); - MFDataType data_type = param_type.data_type(); - - switch (data_type.category()) { - case MFDataType::Single: { - /* Allocates memory for a single constant folded value. */ - const CPPType &cpp_type = data_type.single_type(); - void *buffer = scope.linear_allocator().allocate(cpp_type.size(), cpp_type.alignment()); - GMutableSpan array{cpp_type, buffer, 1}; - params.add_uninitialized_single_output(array); - break; - } - case MFDataType::Vector: { - /* Allocates memory for a constant folded vector. */ - const CPPType &cpp_type = data_type.vector_base_type(); - GVectorArray &vector_array = scope.construct(AT, cpp_type, 1); - params.add_vector_output(vector_array); - break; - } - } - } -} - -static Array add_constant_folded_sockets(const MultiFunction &network_fn, - MFParamsBuilder ¶ms, - ResourceScope &scope, - MFNetwork &network) -{ - Array folded_sockets{network_fn.param_indices().size(), nullptr}; - - for (int param_index : network_fn.param_indices()) { - MFParamType param_type = network_fn.param_type(param_index); - MFDataType data_type = param_type.data_type(); - - const MultiFunction *constant_fn = nullptr; - - switch (data_type.category()) { - case MFDataType::Single: { - const CPPType &cpp_type = data_type.single_type(); - GMutableSpan array = params.computed_array(param_index); - void *buffer = array.data(); - scope.add(buffer, array.type().destruct_fn(), AT); - - constant_fn = &scope.construct(AT, cpp_type, buffer); - break; - } - case MFDataType::Vector: { - GVectorArray &vector_array = params.computed_vector_array(param_index); - GSpan array = vector_array[0]; - constant_fn = &scope.construct(AT, array); - break; - } - } - - MFFunctionNode &folded_node = network.add_function(*constant_fn); - folded_sockets[param_index] = &folded_node.output(0); - } - return folded_sockets; -} - -static Array compute_constant_sockets_and_add_folded_nodes( - MFNetwork &network, Span sockets_to_compute, ResourceScope &scope) -{ - MFNetworkEvaluator network_fn{{}, sockets_to_compute}; - - MFContextBuilder context; - MFParamsBuilder params{network_fn, 1}; - prepare_params_for_constant_folding(network_fn, params, scope); - network_fn.call({0}, params, context); - return add_constant_folded_sockets(network_fn, params, scope, network); -} - -class MyClass { - MFDummyNode node; -}; - -/** - * Find function nodes that always output the same value and replace those with constant nodes. - */ -void constant_folding(MFNetwork &network, ResourceScope &scope) -{ - Vector temporary_nodes; - Vector inputs_to_fold = find_constant_inputs_to_fold(network, temporary_nodes); - if (inputs_to_fold.size() == 0) { - return; - } - - Array folded_sockets = compute_constant_sockets_and_add_folded_nodes( - network, inputs_to_fold, scope); - - for (int i : inputs_to_fold.index_range()) { - MFOutputSocket &original_socket = *inputs_to_fold[i]->origin(); - network.relink(original_socket, *folded_sockets[i]); - } - - network.remove(temporary_nodes.as_span().cast()); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Common Sub-network Elimination - * \{ */ - -static uint64_t compute_node_hash(MFFunctionNode &node, RNG *rng, Span node_hashes) -{ - if (node.function().depends_on_context()) { - return BLI_rng_get_uint(rng); - } - if (node.has_unlinked_inputs()) { - return BLI_rng_get_uint(rng); - } - - uint64_t combined_inputs_hash = 394659347u; - for (MFInputSocket *input_socket : node.inputs()) { - MFOutputSocket *origin_socket = input_socket->origin(); - uint64_t input_hash = BLI_ghashutil_combine_hash(node_hashes[origin_socket->node().id()], - origin_socket->index()); - combined_inputs_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, input_hash); - } - - uint64_t function_hash = node.function().hash(); - uint64_t node_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, function_hash); - return node_hash; -} - -/** - * Produces a hash for every node. Two nodes with the same hash should have a high probability of - * outputting the same values. - */ -static Array compute_node_hashes(MFNetwork &network) -{ - RNG *rng = BLI_rng_new(0); - Array node_hashes(network.node_id_amount()); - Array node_is_hashed(network.node_id_amount(), false); - - /* No dummy nodes are not assumed to output the same values. */ - for (MFDummyNode *node : network.dummy_nodes()) { - uint64_t node_hash = BLI_rng_get_uint(rng); - node_hashes[node->id()] = node_hash; - node_is_hashed[node->id()] = true; - } - - Stack nodes_to_check; - nodes_to_check.push_multiple(network.function_nodes()); - - while (!nodes_to_check.is_empty()) { - MFFunctionNode &node = *nodes_to_check.peek(); - if (node_is_hashed[node.id()]) { - nodes_to_check.pop(); - continue; - } - - /* Make sure that origin nodes are hashed first. */ - bool all_dependencies_ready = true; - for (MFInputSocket *input_socket : node.inputs()) { - MFOutputSocket *origin_socket = input_socket->origin(); - if (origin_socket != nullptr) { - MFNode &origin_node = origin_socket->node(); - if (!node_is_hashed[origin_node.id()]) { - all_dependencies_ready = false; - nodes_to_check.push(&origin_node.as_function()); - } - } - } - if (!all_dependencies_ready) { - continue; - } - - uint64_t node_hash = compute_node_hash(node, rng, node_hashes); - node_hashes[node.id()] = node_hash; - node_is_hashed[node.id()] = true; - nodes_to_check.pop(); - } - - BLI_rng_free(rng); - return node_hashes; -} - -static MultiValueMap group_nodes_by_hash(MFNetwork &network, - Span node_hashes) -{ - MultiValueMap nodes_by_hash; - for (int id : IndexRange(network.node_id_amount())) { - MFNode *node = network.node_or_null_by_id(id); - if (node != nullptr) { - uint64_t node_hash = node_hashes[id]; - nodes_by_hash.add(node_hash, node); - } - } - return nodes_by_hash; -} - -static bool functions_are_equal(const MultiFunction &a, const MultiFunction &b) -{ - if (&a == &b) { - return true; - } - if (typeid(a) == typeid(b)) { - return a.equals(b); - } - return false; -} - -static bool nodes_output_same_values(DisjointSet &cache, const MFNode &a, const MFNode &b) -{ - if (cache.in_same_set(a.id(), b.id())) { - return true; - } - - if (a.is_dummy() || b.is_dummy()) { - return false; - } - if (!functions_are_equal(a.as_function().function(), b.as_function().function())) { - return false; - } - for (int i : a.inputs().index_range()) { - const MFOutputSocket *origin_a = a.input(i).origin(); - const MFOutputSocket *origin_b = b.input(i).origin(); - if (origin_a == nullptr || origin_b == nullptr) { - return false; - } - if (!nodes_output_same_values(cache, origin_a->node(), origin_b->node())) { - return false; - } - } - - cache.join(a.id(), b.id()); - return true; -} - -static void relink_duplicate_nodes(MFNetwork &network, - MultiValueMap &nodes_by_hash) -{ - DisjointSet same_node_cache{network.node_id_amount()}; - - for (Span nodes_with_same_hash : nodes_by_hash.values()) { - if (nodes_with_same_hash.size() <= 1) { - continue; - } - - Vector nodes_to_check = nodes_with_same_hash; - while (nodes_to_check.size() >= 2) { - Vector remaining_nodes; - - MFNode &deduplicated_node = *nodes_to_check[0]; - for (MFNode *node : nodes_to_check.as_span().drop_front(1)) { - /* This is true with fairly high probability, but hash collisions can happen. So we have to - * check if the node actually output the same values. */ - if (nodes_output_same_values(same_node_cache, deduplicated_node, *node)) { - for (int i : deduplicated_node.outputs().index_range()) { - network.relink(node->output(i), deduplicated_node.output(i)); - } - } - else { - remaining_nodes.append(node); - } - } - nodes_to_check = std::move(remaining_nodes); - } - } -} - -/** - * Tries to detect duplicate sub-networks and eliminates them. This can help quite a lot when node - * groups were used to create the network. - */ -void common_subnetwork_elimination(MFNetwork &network) -{ - Array node_hashes = compute_node_hashes(network); - MultiValueMap nodes_by_hash = group_nodes_by_hash(network, node_hashes); - relink_duplicate_nodes(network, nodes_by_hash); -} - -/** \} */ - -} // namespace blender::fn::mf_network_optimization diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc deleted file mode 100644 index 7b9738e5ca4..00000000000 --- a/source/blender/functions/tests/FN_multi_function_network_test.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* Apache License, Version 2.0 */ - -#include "testing/testing.h" - -#include "FN_multi_function_builder.hh" -#include "FN_multi_function_network.hh" -#include "FN_multi_function_network_evaluation.hh" - -namespace blender::fn::tests { -namespace { - -TEST(multi_function_network, Test1) -{ - CustomMF_SI_SO add_10_fn("add 10", [](int value) { return value + 10; }); - CustomMF_SI_SI_SO multiply_fn("multiply", [](int a, int b) { return a * b; }); - - MFNetwork network; - - MFNode &node1 = network.add_function(add_10_fn); - MFNode &node2 = network.add_function(multiply_fn); - MFOutputSocket &input_socket = network.add_input("Input", MFDataType::ForSingle()); - MFInputSocket &output_socket = network.add_output("Output", MFDataType::ForSingle()); - network.add_link(node1.output(0), node2.input(0)); - network.add_link(node1.output(0), node2.input(1)); - network.add_link(node2.output(0), output_socket); - network.add_link(input_socket, node1.input(0)); - - MFNetworkEvaluator network_fn{{&input_socket}, {&output_socket}}; - - { - Array values = {4, 6, 1, 2, 0}; - Array results(values.size(), 0); - - MFParamsBuilder params(network_fn, values.size()); - params.add_readonly_single_input(values.as_span()); - params.add_uninitialized_single_output(results.as_mutable_span()); - - MFContextBuilder context; - - network_fn.call({0, 2, 3, 4}, params, context); - - EXPECT_EQ(results[0], 14 * 14); - EXPECT_EQ(results[1], 0); - EXPECT_EQ(results[2], 11 * 11); - EXPECT_EQ(results[3], 12 * 12); - EXPECT_EQ(results[4], 10 * 10); - } - { - int value = 3; - Array results(5, 0); - - MFParamsBuilder params(network_fn, results.size()); - params.add_readonly_single_input(&value); - params.add_uninitialized_single_output(results.as_mutable_span()); - - MFContextBuilder context; - - network_fn.call({1, 2, 4}, params, context); - - EXPECT_EQ(results[0], 0); - EXPECT_EQ(results[1], 13 * 13); - EXPECT_EQ(results[2], 13 * 13); - EXPECT_EQ(results[3], 0); - EXPECT_EQ(results[4], 13 * 13); - } -} - -class ConcatVectorsFunction : public MultiFunction { - public: - ConcatVectorsFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Concat Vectors"}; - signature.vector_mutable("A"); - signature.vector_input("B"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - GVectorArray &a = params.vector_mutable(0); - const GVVectorArray &b = params.readonly_vector_input(1); - a.extend(mask, b); - } -}; - -class AppendFunction : public MultiFunction { - public: - AppendFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Append"}; - signature.vector_mutable("Vector"); - signature.single_input("Value"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - GVectorArray_TypedMutableRef vectors = params.vector_mutable(0); - const VArray &values = params.readonly_single_input(1); - - for (int64_t i : mask) { - vectors.append(i, values[i]); - } - } -}; - -class SumVectorFunction : public MultiFunction { - public: - SumVectorFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Sum Vectors"}; - signature.vector_input("Vector"); - signature.single_output("Sum"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - const VVectorArray &vectors = params.readonly_vector_input(0); - MutableSpan sums = params.uninitialized_single_output(1); - - for (int64_t i : mask) { - int sum = 0; - for (int j : IndexRange(vectors.get_vector_size(i))) { - sum += vectors.get_vector_element(i, j); - } - sums[i] = sum; - } - } -}; - -class CreateRangeFunction : public MultiFunction { - public: - CreateRangeFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Create Range"}; - signature.single_input("Size"); - signature.vector_output("Range"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - const VArray &sizes = params.readonly_single_input(0, "Size"); - GVectorArray_TypedMutableRef ranges = params.vector_output(1, "Range"); - - for (int64_t i : mask) { - int size = sizes[i]; - for (int j : IndexRange(size)) { - ranges.append(i, j); - } - } - } -}; - -TEST(multi_function_network, Test2) -{ - CustomMF_SI_SO add_3_fn("add 3", [](int value) { return value + 3; }); - - ConcatVectorsFunction concat_vectors_fn; - AppendFunction append_fn; - SumVectorFunction sum_fn; - CreateRangeFunction create_range_fn; - - MFNetwork network; - - MFOutputSocket &input1 = network.add_input("Input 1", MFDataType::ForVector()); - MFOutputSocket &input2 = network.add_input("Input 2", MFDataType::ForSingle()); - MFInputSocket &output1 = network.add_output("Output 1", MFDataType::ForVector()); - MFInputSocket &output2 = network.add_output("Output 2", MFDataType::ForSingle()); - - MFNode &node1 = network.add_function(add_3_fn); - MFNode &node2 = network.add_function(create_range_fn); - MFNode &node3 = network.add_function(concat_vectors_fn); - MFNode &node4 = network.add_function(sum_fn); - MFNode &node5 = network.add_function(append_fn); - MFNode &node6 = network.add_function(sum_fn); - - network.add_link(input2, node1.input(0)); - network.add_link(node1.output(0), node2.input(0)); - network.add_link(node2.output(0), node3.input(1)); - network.add_link(input1, node3.input(0)); - network.add_link(input1, node4.input(0)); - network.add_link(node4.output(0), node5.input(1)); - network.add_link(node3.output(0), node5.input(0)); - network.add_link(node5.output(0), node6.input(0)); - network.add_link(node3.output(0), output1); - network.add_link(node6.output(0), output2); - - // std::cout << network.to_dot() << "\n\n"; - - MFNetworkEvaluator network_fn{{&input1, &input2}, {&output1, &output2}}; - - { - Array input_value_1 = {3, 6}; - int input_value_2 = 4; - - GVectorArray output_value_1(CPPType::get(), 5); - Array output_value_2(5, -1); - - MFParamsBuilder params(network_fn, 5); - GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5}; - params.add_readonly_vector_input(inputs_1); - params.add_readonly_single_input(&input_value_2); - params.add_vector_output(output_value_1); - params.add_uninitialized_single_output(output_value_2.as_mutable_span()); - - MFContextBuilder context; - - network_fn.call({1, 2, 4}, params, context); - - EXPECT_EQ(output_value_1[0].size(), 0); - EXPECT_EQ(output_value_1[1].size(), 9); - EXPECT_EQ(output_value_1[2].size(), 9); - EXPECT_EQ(output_value_1[3].size(), 0); - EXPECT_EQ(output_value_1[4].size(), 9); - - EXPECT_EQ(output_value_2[0], -1); - EXPECT_EQ(output_value_2[1], 39); - EXPECT_EQ(output_value_2[2], 39); - EXPECT_EQ(output_value_2[3], -1); - EXPECT_EQ(output_value_2[4], 39); - } - { - GVectorArray input_value_1(CPPType::get(), 3); - GVectorArray_TypedMutableRef input_value_1_ref{input_value_1}; - input_value_1_ref.extend(0, {3, 4, 5}); - input_value_1_ref.extend(1, {1, 2}); - - Array input_value_2 = {4, 2, 3}; - - GVectorArray output_value_1(CPPType::get(), 3); - Array output_value_2(3, -1); - - MFParamsBuilder params(network_fn, 3); - params.add_readonly_vector_input(input_value_1); - params.add_readonly_single_input(input_value_2.as_span()); - params.add_vector_output(output_value_1); - params.add_uninitialized_single_output(output_value_2.as_mutable_span()); - - MFContextBuilder context; - - network_fn.call({0, 1, 2}, params, context); - - EXPECT_EQ(output_value_1[0].size(), 10); - EXPECT_EQ(output_value_1[1].size(), 7); - EXPECT_EQ(output_value_1[2].size(), 6); - - EXPECT_EQ(output_value_2[0], 45); - EXPECT_EQ(output_value_2[1], 16); - EXPECT_EQ(output_value_2[2], 15); - } -} - -} // namespace -} // namespace blender::fn::tests diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc index 3d73e020eb2..91c72a51dd6 100644 --- a/source/blender/functions/tests/FN_multi_function_test.cc +++ b/source/blender/functions/tests/FN_multi_function_test.cc @@ -4,6 +4,7 @@ #include "FN_multi_function.hh" #include "FN_multi_function_builder.hh" +#include "FN_multi_function_test_common.hh" namespace blender::fn::tests { namespace { @@ -59,33 +60,6 @@ TEST(multi_function, AddFunction) EXPECT_EQ(output[2], 36); } -class AddPrefixFunction : public MultiFunction { - public: - AddPrefixFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Add Prefix"}; - signature.single_input("Prefix"); - signature.single_mutable("Strings"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - const VArray &prefixes = params.readonly_single_input(0, "Prefix"); - MutableSpan strings = params.single_mutable(1, "Strings"); - - for (int64_t i : mask) { - strings[i] = prefixes[i] + strings[i]; - } - } -}; - TEST(multi_function, AddPrefixFunction) { AddPrefixFunction fn; @@ -113,43 +87,13 @@ TEST(multi_function, AddPrefixFunction) EXPECT_EQ(strings[3], "ABAnother much longer string to trigger an allocation"); } -class CreateRangeFunction : public MultiFunction { - public: - CreateRangeFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Create Range"}; - signature.single_input("Size"); - signature.vector_output("Range"); - return signature.build(); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - const VArray &sizes = params.readonly_single_input(0, "Size"); - GVectorArray &ranges = params.vector_output(1, "Range"); - - for (int64_t i : mask) { - uint size = sizes[i]; - for (uint j : IndexRange(size)) { - ranges.append(i, &j); - } - } - } -}; - TEST(multi_function, CreateRangeFunction) { CreateRangeFunction fn; - GVectorArray ranges(CPPType::get(), 5); - GVectorArray_TypedMutableRef ranges_ref{ranges}; - Array sizes = {3, 0, 6, 1, 4}; + GVectorArray ranges(CPPType::get(), 5); + GVectorArray_TypedMutableRef ranges_ref{ranges}; + Array sizes = {3, 0, 6, 1, 4}; MFParamsBuilder params(fn, ranges.size()); params.add_readonly_single_input(sizes.as_span()); @@ -172,34 +116,6 @@ TEST(multi_function, CreateRangeFunction) EXPECT_EQ(ranges_ref[2][1], 1); } -class GenericAppendFunction : public MultiFunction { - private: - MFSignature signature_; - - public: - GenericAppendFunction(const CPPType &type) - { - MFSignatureBuilder signature{"Append"}; - signature.vector_mutable("Vector", type); - signature.single_input("Value", type); - signature_ = signature.build(); - this->set_signature(&signature_); - } - - void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override - { - GVectorArray &vectors = params.vector_mutable(0, "Vector"); - const GVArray &values = params.readonly_single_input(1, "Value"); - - for (int64_t i : mask) { - BUFFER_FOR_CPP_TYPE_VALUE(values.type(), buffer); - values.get(i, buffer); - vectors.append(i, buffer); - values.type().destruct(buffer); - } - } -}; - TEST(multi_function, GenericAppendFunction) { GenericAppendFunction fn(CPPType::get()); diff --git a/source/blender/functions/tests/FN_multi_function_test_common.hh b/source/blender/functions/tests/FN_multi_function_test_common.hh new file mode 100644 index 00000000000..51c8fac8a96 --- /dev/null +++ b/source/blender/functions/tests/FN_multi_function_test_common.hh @@ -0,0 +1,174 @@ +/* Apache License, Version 2.0 */ + +#include "FN_multi_function.hh" + +namespace blender::fn::tests { + +class AddPrefixFunction : public MultiFunction { + public: + AddPrefixFunction() + { + static MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static MFSignature create_signature() + { + MFSignatureBuilder signature{"Add Prefix"}; + signature.single_input("Prefix"); + signature.single_mutable("Strings"); + return signature.build(); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + const VArray &prefixes = params.readonly_single_input(0, "Prefix"); + MutableSpan strings = params.single_mutable(1, "Strings"); + + for (int64_t i : mask) { + strings[i] = prefixes[i] + strings[i]; + } + } +}; + +class CreateRangeFunction : public MultiFunction { + public: + CreateRangeFunction() + { + static MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static MFSignature create_signature() + { + MFSignatureBuilder signature{"Create Range"}; + signature.single_input("Size"); + signature.vector_output("Range"); + return signature.build(); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + const VArray &sizes = params.readonly_single_input(0, "Size"); + GVectorArray &ranges = params.vector_output(1, "Range"); + + for (int64_t i : mask) { + int size = sizes[i]; + for (int j : IndexRange(size)) { + ranges.append(i, &j); + } + } + } +}; + +class GenericAppendFunction : public MultiFunction { + private: + MFSignature signature_; + + public: + GenericAppendFunction(const CPPType &type) + { + MFSignatureBuilder signature{"Append"}; + signature.vector_mutable("Vector", type); + signature.single_input("Value", type); + signature_ = signature.build(); + this->set_signature(&signature_); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + GVectorArray &vectors = params.vector_mutable(0, "Vector"); + const GVArray &values = params.readonly_single_input(1, "Value"); + + for (int64_t i : mask) { + BUFFER_FOR_CPP_TYPE_VALUE(values.type(), buffer); + values.get(i, buffer); + vectors.append(i, buffer); + values.type().destruct(buffer); + } + } +}; + +class ConcatVectorsFunction : public MultiFunction { + public: + ConcatVectorsFunction() + { + static MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static MFSignature create_signature() + { + MFSignatureBuilder signature{"Concat Vectors"}; + signature.vector_mutable("A"); + signature.vector_input("B"); + return signature.build(); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + GVectorArray &a = params.vector_mutable(0); + const GVVectorArray &b = params.readonly_vector_input(1); + a.extend(mask, b); + } +}; + +class AppendFunction : public MultiFunction { + public: + AppendFunction() + { + static MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static MFSignature create_signature() + { + MFSignatureBuilder signature{"Append"}; + signature.vector_mutable("Vector"); + signature.single_input("Value"); + return signature.build(); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + GVectorArray_TypedMutableRef vectors = params.vector_mutable(0); + const VArray &values = params.readonly_single_input(1); + + for (int64_t i : mask) { + vectors.append(i, values[i]); + } + } +}; + +class SumVectorFunction : public MultiFunction { + public: + SumVectorFunction() + { + static MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static MFSignature create_signature() + { + MFSignatureBuilder signature{"Sum Vectors"}; + signature.vector_input("Vector"); + signature.single_output("Sum"); + return signature.build(); + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + const VVectorArray &vectors = params.readonly_vector_input(0); + MutableSpan sums = params.uninitialized_single_output(1); + + for (int64_t i : mask) { + int sum = 0; + for (int j : IndexRange(vectors.get_vector_size(i))) { + sum += vectors.get_vector_element(i, j); + } + sums[i] = sum; + } + } +}; + +} // namespace blender::fn::tests diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 3853b345c14..620c7ef438a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -84,7 +84,8 @@ #include "NOD_derived_node_tree.hh" #include "NOD_geometry.h" #include "NOD_geometry_nodes_eval_log.hh" -#include "NOD_node_tree_multi_function.hh" + +#include "FN_multi_function.hh" using blender::destruct_ptr; using blender::float3; @@ -858,7 +859,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, { blender::ResourceScope scope; blender::LinearAllocator<> &allocator = scope.linear_allocator(); - blender::nodes::MultiFunctionByNode mf_by_node = get_multi_function_per_node(tree, scope); + blender::nodes::NodeMultiFunctions mf_by_node{tree, scope}; Map group_inputs; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 47dfd9bc8f6..5646e37707c 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -836,7 +836,7 @@ class GeometryNodesEvaluator { } /* Use the multi-function implementation if it exists. */ - const MultiFunction *multi_function = params_.mf_by_node->lookup_default(node, nullptr); + const MultiFunction *multi_function = params_.mf_by_node->try_get(node); if (multi_function != nullptr) { this->execute_multi_function_node(node, *multi_function, node_state); return; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh index d8c60d31986..5151be07aa2 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh @@ -20,12 +20,14 @@ #include "NOD_derived_node_tree.hh" #include "NOD_geometry_nodes_eval_log.hh" -#include "NOD_node_tree_multi_function.hh" +#include "NOD_multi_function.hh" #include "FN_generic_pointer.hh" #include "DNA_modifier_types.h" +#include "FN_multi_function.hh" + namespace geo_log = blender::nodes::geometry_nodes_eval_log; namespace blender::modifiers::geometry_nodes { @@ -45,7 +47,7 @@ struct GeometryNodesEvaluationParams { * necessary in all cases. Sometimes `log_socket_value_fn` might just want to look at the value * and then it can be freed. */ Vector force_compute_sockets; - nodes::MultiFunctionByNode *mf_by_node; + nodes::NodeMultiFunctions *mf_by_node; const NodesModifierData *modifier_; Depsgraph *depsgraph; Object *self_object; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 46fb9f54bfe..8680fcee49a 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -345,11 +345,10 @@ set(SRC intern/node_common.c intern/node_exec.cc intern/node_geometry_exec.cc + intern/node_multi_function.cc intern/node_socket.cc - intern/node_tree_multi_function.cc intern/node_tree_ref.cc intern/node_util.c - intern/type_callbacks.cc intern/type_conversions.cc composite/node_composite_util.h @@ -366,13 +365,12 @@ set(SRC NOD_geometry_exec.hh NOD_geometry_nodes_eval_log.hh NOD_math_functions.hh - NOD_node_tree_multi_function.hh + NOD_multi_function.hh NOD_node_tree_ref.hh NOD_shader.h NOD_socket.h NOD_static_types.h NOD_texture.h - NOD_type_callbacks.hh NOD_type_conversions.hh intern/node_common.h intern/node_exec.h diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh new file mode 100644 index 00000000000..2f4b104fb4c --- /dev/null +++ b/source/blender/nodes/NOD_multi_function.hh @@ -0,0 +1,130 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "FN_multi_function.hh" + +#include "DNA_node_types.h" + +#include "NOD_derived_node_tree.hh" + +namespace blender::nodes { + +using namespace fn::multi_function_types; + +class NodeMultiFunctions; + +/** + * Utility class to help nodes build a multi-function for themselves. + */ +class NodeMultiFunctionBuilder : NonCopyable, NonMovable { + private: + ResourceScope &resource_scope_; + bNode &node_; + bNodeTree &tree_; + const MultiFunction *built_fn_ = nullptr; + + friend NodeMultiFunctions; + + public: + NodeMultiFunctionBuilder(ResourceScope &resource_scope, bNode &node, bNodeTree &tree); + + /** + * Assign a multi-function for the current node. The input and output parameters of the function + * have to match the available sockets in the node. + */ + void set_matching_fn(const MultiFunction *fn); + void set_matching_fn(const MultiFunction &fn); + + /** + * Utility method for creating and assigning a multi-function when it can't have a static + * lifetime. + */ + template void construct_and_set_matching_fn(Args &&...args); + + bNode &node(); + bNodeTree &tree(); + + ResourceScope &resource_scope(); +}; + +/** + * Gives access to multi-functions for all nodes in a node tree that support them. + */ +class NodeMultiFunctions { + private: + Map map_; + + public: + NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope); + + const MultiFunction *try_get(const DNode &node) const; +}; + +/* -------------------------------------------------------------------- + * NodeMultiFunctionBuilder inline methods. + */ + +inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(ResourceScope &resource_scope, + bNode &node, + bNodeTree &tree) + : resource_scope_(resource_scope), node_(node), tree_(tree) +{ +} + +inline bNode &NodeMultiFunctionBuilder::node() +{ + return node_; +} + +inline bNodeTree &NodeMultiFunctionBuilder::tree() +{ + return tree_; +} + +inline ResourceScope &NodeMultiFunctionBuilder::resource_scope() +{ + return resource_scope_; +} + +inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn) +{ + built_fn_ = fn; +} + +inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction &fn) +{ + this->set_matching_fn(&fn); +} + +template +inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...args) +{ + const T &fn = resource_scope_.construct(__func__, std::forward(args)...); + this->set_matching_fn(&fn); +} + +/* -------------------------------------------------------------------- + * NodeMultiFunctions inline methods. + */ + +inline const MultiFunction *NodeMultiFunctions::try_get(const DNode &node) const +{ + return map_.lookup_default(node->bnode(), nullptr); +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh deleted file mode 100644 index 7eeeaef0b98..00000000000 --- a/source/blender/nodes/NOD_node_tree_multi_function.hh +++ /dev/null @@ -1,390 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -/** \file - * \ingroup nodes - * - * This file allows you to generate a multi-function network from a user-generated node tree. - */ - -#include "FN_multi_function_builder.hh" -#include "FN_multi_function_network.hh" - -#include "NOD_derived_node_tree.hh" -#include "NOD_type_callbacks.hh" - -#include "BLI_multi_value_map.hh" -#include "BLI_resource_scope.hh" - -namespace blender::nodes { - -/** - * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This - * is necessary for further processing of a multi-function network that has been generated from a - * node tree. - */ -class MFNetworkTreeMap { - private: - /** - * Store by id instead of using a hash table to avoid unnecessary hash table lookups. - * - * Input sockets in a node tree can have multiple corresponding sockets in the generated - * MFNetwork. This is because nodes are allowed to expand into multiple multi-function nodes. - */ - const DerivedNodeTree &tree_; - fn::MFNetwork &network_; - MultiValueMap sockets_by_dsocket_; - - public: - MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network) - : tree_(tree), network_(network) - { - } - - const DerivedNodeTree &tree() const - { - return tree_; - } - - const fn::MFNetwork &network() const - { - return network_; - } - - fn::MFNetwork &network() - { - return network_; - } - - void add(const DSocket &dsocket, fn::MFSocket &socket) - { - BLI_assert(dsocket->is_input() == socket.is_input()); - BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty()); - sockets_by_dsocket_.add(dsocket, &socket); - } - - void add(const DInputSocket &dsocket, fn::MFInputSocket &socket) - { - sockets_by_dsocket_.add(dsocket, &socket); - } - - void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket) - { - /* There can be at most one matching output socket. */ - BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty()); - sockets_by_dsocket_.add(dsocket, &socket); - } - - void add(const DTreeContext &context, - Span dsockets, - Span sockets) - { - assert_same_size(dsockets, sockets); - for (int i : dsockets.index_range()) { - this->add(DInputSocket(&context, dsockets[i]), *sockets[i]); - } - } - - void add(const DTreeContext &context, - Span dsockets, - Span sockets) - { - assert_same_size(dsockets, sockets); - for (int i : dsockets.index_range()) { - this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]); - } - } - - void add_try_match(const DNode &dnode, fn::MFNode &node) - { - this->add_try_match(*dnode.context(), - dnode->inputs().cast(), - node.inputs().cast()); - this->add_try_match(*dnode.context(), - dnode->outputs().cast(), - node.outputs().cast()); - } - - void add_try_match(const DTreeContext &context, - Span dsockets, - Span sockets) - { - this->add_try_match( - context, dsockets.cast(), sockets.cast()); - } - - void add_try_match(const DTreeContext &context, - Span dsockets, - Span sockets) - { - this->add_try_match( - context, dsockets.cast(), sockets.cast()); - } - - void add_try_match(const DTreeContext &context, - Span dsockets, - Span sockets) - { - int used_sockets = 0; - for (const SocketRef *dsocket : dsockets) { - if (!dsocket->is_available()) { - continue; - } - if (!socket_is_mf_data_socket(*dsocket->typeinfo())) { - continue; - } - fn::MFSocket *socket = sockets[used_sockets]; - this->add(DSocket(&context, dsocket), *socket); - used_sockets++; - } - } - - fn::MFOutputSocket &lookup(const DOutputSocket &dsocket) - { - return sockets_by_dsocket_.lookup(dsocket)[0]->as_output(); - } - - Span lookup(const DInputSocket &dsocket) - { - return sockets_by_dsocket_.lookup(dsocket).cast(); - } - - fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket) - { - Span sockets = this->lookup(dsocket); - BLI_assert(sockets.size() == 1); - fn::MFInputSocket &socket = *sockets[0]; - BLI_assert(socket.node().is_dummy()); - return socket; - } - - fn::MFOutputSocket &lookup_dummy(const DOutputSocket &dsocket) - { - fn::MFOutputSocket &socket = this->lookup(dsocket); - BLI_assert(socket.node().is_dummy()); - return socket; - } - - bool is_mapped(const DSocket &dsocket) const - { - return !sockets_by_dsocket_.lookup(dsocket).is_empty(); - } -}; - -/** - * This data is necessary throughout the generation of a MFNetwork from a node tree. - */ -struct CommonMFNetworkBuilderData { - ResourceScope &scope; - fn::MFNetwork &network; - MFNetworkTreeMap &network_map; - const DerivedNodeTree &tree; -}; - -class MFNetworkBuilderBase { - protected: - CommonMFNetworkBuilderData &common_; - - public: - MFNetworkBuilderBase(CommonMFNetworkBuilderData &common) : common_(common) - { - } - - /** - * Returns the network that is currently being built. - */ - fn::MFNetwork &network() - { - return common_.network; - } - - /** - * Returns the map between the node tree and the multi-function network that is being built. - */ - MFNetworkTreeMap &network_map() - { - return common_.network_map; - } - - /** - * Returns a resource collector that will only be destructed after the multi-function network is - * destructed. - */ - ResourceScope &resource_scope() - { - return common_.scope; - } - - /** - * Constructs a new function that will live at least as long as the MFNetwork. - */ - template T &construct_fn(Args &&...args) - { - BLI_STATIC_ASSERT((std::is_base_of_v), ""); - void *buffer = common_.scope.linear_allocator().allocate(sizeof(T), alignof(T)); - T *fn = new (buffer) T(std::forward(args)...); - common_.scope.add(destruct_ptr(fn), fn->name().c_str()); - return *fn; - } -}; - -/** - * This class is used by socket implementations to define how an unlinked input socket is handled - * in a multi-function network. - */ -class SocketMFNetworkBuilder : public MFNetworkBuilderBase { - private: - bNodeSocket *bsocket_; - fn::MFOutputSocket *built_socket_ = nullptr; - - public: - SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket) - : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket()) - { - } - - /** - * Returns the socket that is currently being built. - */ - bNodeSocket &bsocket() - { - return *bsocket_; - } - - /** - * Utility method that returns bsocket->default_value for the current socket. - */ - template T *socket_default_value() - { - return static_cast(bsocket_->default_value); - } - - /** - * Builds a function node for that socket that outputs the given constant value. - */ - template void set_constant_value(T value) - { - this->construct_generator_fn>(std::move(value)); - } - void set_constant_value(const CPPType &type, const void *value) - { - /* The value has live as long as the generated mf network. */ - this->construct_generator_fn(type, value); - } - - template void construct_generator_fn(Args &&...args) - { - const fn::MultiFunction &fn = this->construct_fn(std::forward(args)...); - this->set_generator_fn(fn); - } - - /** - * Uses the first output of the given multi-function as value of the socket. - */ - void set_generator_fn(const fn::MultiFunction &fn) - { - fn::MFFunctionNode &node = common_.network.add_function(fn); - this->set_socket(node.output(0)); - } - - /** - * Define a multi-function socket that outputs the value of the bsocket. - */ - void set_socket(fn::MFOutputSocket &socket) - { - built_socket_ = &socket; - } - - fn::MFOutputSocket *built_socket() - { - return built_socket_; - } -}; - -/** - * This class is used by node implementations to define how a user-level node expands into - * multi-function nodes internally. - */ -class NodeMFNetworkBuilder : public MFNetworkBuilderBase { - private: - DNode dnode_; - - public: - NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode) - : MFNetworkBuilderBase(common), dnode_(dnode) - { - } - - /** - * Tells the builder to build a function that corresponds to the node that is being built. It - * will try to match up sockets. - */ - template T &construct_and_set_matching_fn(Args &&...args) - { - T &function = this->construct_fn(std::forward(args)...); - this->set_matching_fn(function); - return function; - } - - const fn::MultiFunction &get_not_implemented_fn() - { - return this->get_default_fn("Not Implemented (" + dnode_->name() + ")"); - } - - const fn::MultiFunction &get_default_fn(StringRef name); - - const void set_not_implemented() - { - this->set_matching_fn(this->get_not_implemented_fn()); - } - - /** - * Tells the builder that the given function corresponds to the node that is being built. It will - * try to match up sockets. For that it skips unavailable and non-data sockets. - */ - void set_matching_fn(const fn::MultiFunction &function) - { - fn::MFFunctionNode &node = common_.network.add_function(function); - common_.network_map.add_try_match(dnode_, node); - } - - /** - * Returns the node that is currently being built. - */ - bNode &bnode() - { - return *dnode_->bnode(); - } - - /** - * Returns the node that is currently being built. - */ - const DNode &dnode() const - { - return dnode_; - } -}; - -MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, - const DerivedNodeTree &tree, - ResourceScope &scope); - -using MultiFunctionByNode = Map; -MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope); - -} // namespace blender::nodes diff --git a/source/blender/nodes/NOD_type_callbacks.hh b/source/blender/nodes/NOD_type_callbacks.hh deleted file mode 100644 index 2be78f929db..00000000000 --- a/source/blender/nodes/NOD_type_callbacks.hh +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include - -#include "BKE_node.h" - -#include "FN_multi_function_data_type.hh" - -namespace blender::nodes { - -using fn::CPPType; -using fn::MFDataType; - -std::optional socket_mf_type_get(const bNodeSocketType &stype); -bool socket_is_mf_data_socket(const bNodeSocketType &stype); -void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder); - -} // namespace blender::nodes diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index 9fbd6712827..96a8f29c3e9 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -30,7 +30,7 @@ #include "BLT_translation.h" #include "NOD_function.h" -#include "NOD_node_tree_multi_function.hh" +#include "NOD_multi_function.hh" #include "node_util.h" diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index 7a83ff8e016..0ba9080918c 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -58,7 +58,7 @@ static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char BLI_strncpy(label, IFACE_(name), maxlen); } -static const blender::fn::MultiFunction &get_multi_function(bNode &bnode) +static const blender::fn::MultiFunction *get_multi_function(bNode &bnode) { static blender::fn::CustomMF_SI_SI_SO and_fn{ "And", [](bool a, bool b) { return a && b; }}; @@ -68,20 +68,21 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode) switch (bnode.custom1) { case NODE_BOOLEAN_MATH_AND: - return and_fn; + return &and_fn; case NODE_BOOLEAN_MATH_OR: - return or_fn; + return &or_fn; case NODE_BOOLEAN_MATH_NOT: - return not_fn; + return ¬_fn; } - BLI_assert(false); - return blender::fn::dummy_multi_function; + BLI_assert_unreachable(); + return nullptr; } -static void node_boolean_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_boolean_math_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode()); + const blender::fn::MultiFunction *fn = get_multi_function(builder.node()); builder.set_matching_fn(fn); } @@ -93,7 +94,7 @@ void register_node_type_fn_boolean_math() node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out); node_type_label(&ntype, node_boolean_math_label); node_type_update(&ntype, node_boolean_math_update); - ntype.expand_in_mf_network = node_boolean_expand_in_mf_network; + ntype.build_multi_function = fn_node_boolean_math_build_multi_function; ntype.draw_buttons = fn_node_boolean_math_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index 6c8df8f2ea0..16ffb761a15 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -64,7 +64,7 @@ static void node_float_compare_label(bNodeTree *UNUSED(ntree), BLI_strncpy(label, IFACE_(name), maxlen); } -static const blender::fn::MultiFunction &get_multi_function(bNode &node) +static const blender::fn::MultiFunction *get_multi_function(bNode &node) { static blender::fn::CustomMF_SI_SI_SO less_than_fn{ "Less Than", [](float a, float b) { return a < b; }}; @@ -81,26 +81,27 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &node) switch (node.custom1) { case NODE_FLOAT_COMPARE_LESS_THAN: - return less_than_fn; + return &less_than_fn; case NODE_FLOAT_COMPARE_LESS_EQUAL: - return less_equal_fn; + return &less_equal_fn; case NODE_FLOAT_COMPARE_GREATER_THAN: - return greater_than_fn; + return &greater_than_fn; case NODE_FLOAT_COMPARE_GREATER_EQUAL: - return greater_equal_fn; + return &greater_equal_fn; case NODE_FLOAT_COMPARE_EQUAL: - return equal_fn; + return &equal_fn; case NODE_FLOAT_COMPARE_NOT_EQUAL: - return not_equal_fn; + return ¬_equal_fn; } - BLI_assert(false); - return blender::fn::dummy_multi_function; + BLI_assert_unreachable(); + return nullptr; } -static void node_float_compare_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_float_compare_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode()); + const blender::fn::MultiFunction *fn = get_multi_function(builder.node()); builder.set_matching_fn(fn); } @@ -112,7 +113,7 @@ void register_node_type_fn_float_compare() node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out); node_type_label(&ntype, node_float_compare_label); node_type_update(&ntype, node_float_compare_update); - ntype.expand_in_mf_network = node_float_compare_expand_in_mf_network; + ntype.build_multi_function = fn_node_float_compare_build_multi_function; ntype.draw_buttons = geo_node_float_compare_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 26cde576400..52acfefe615 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -50,7 +50,7 @@ static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char BLI_strncpy(label, IFACE_(name), maxlen); } -static const blender::fn::MultiFunction &get_multi_function(bNode &bnode) +static const blender::fn::MultiFunction *get_multi_function(bNode &bnode) { static blender::fn::CustomMF_SI_SO round_fn{"Round", [](float a) { return (int)round(a); }}; @@ -63,22 +63,23 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode) switch (static_cast(bnode.custom1)) { case FN_NODE_FLOAT_TO_INT_ROUND: - return round_fn; + return &round_fn; case FN_NODE_FLOAT_TO_INT_FLOOR: - return floor_fn; + return &floor_fn; case FN_NODE_FLOAT_TO_INT_CEIL: - return ceil_fn; + return &ceil_fn; case FN_NODE_FLOAT_TO_INT_TRUNCATE: - return trunc_fn; + return &trunc_fn; } BLI_assert_unreachable(); - return blender::fn::dummy_multi_function; + return nullptr; } -static void node_float_to_int_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_float_to_int_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode()); + const blender::fn::MultiFunction *fn = get_multi_function(builder.node()); builder.set_matching_fn(fn); } @@ -89,7 +90,7 @@ void register_node_type_fn_float_to_int() fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, fn_node_float_to_int_in, fn_node_float_to_int_out); node_type_label(&ntype, node_float_to_int_label); - ntype.expand_in_mf_network = node_float_to_int_expand_in_mf_network; + ntype.build_multi_function = fn_node_float_to_int_build_multi_function; ntype.draw_buttons = fn_node_float_to_int_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index f16bdef2f38..560ace57aba 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -29,14 +29,14 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "string", 0, "", ICON_NONE); } -static void fn_node_input_string_expand_in_mf_network( - blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_input_string_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); NodeInputString *node_storage = static_cast(bnode.storage); std::string string = std::string((node_storage->string) ? node_storage->string : ""); - - builder.construct_and_set_matching_fn>(string); + builder.construct_and_set_matching_fn>( + std::move(string)); } static void fn_node_input_string_init(bNodeTree *UNUSED(ntree), bNode *node) @@ -78,7 +78,7 @@ void register_node_type_fn_input_string() node_type_socket_templates(&ntype, nullptr, fn_node_input_string_out); node_type_init(&ntype, fn_node_input_string_init); node_type_storage(&ntype, "NodeInputString", fn_node_input_string_free, fn_node_string_copy); - ntype.expand_in_mf_network = fn_node_input_string_expand_in_mf_network; + ntype.build_multi_function = fn_node_input_string_build_multi_function; ntype.draw_buttons = fn_node_input_string_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc index 2cd4eb1d9df..244c045de9a 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -32,16 +32,14 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(col, ptr, "vector", UI_ITEM_R_EXPAND, "", ICON_NONE); } -static void fn_node_vector_input_expand_in_mf_network( - blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_vector_input_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); NodeInputVector *node_storage = static_cast(bnode.storage); blender::float3 vector(node_storage->vector); - builder.construct_and_set_matching_fn>(vector); } - static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector), @@ -58,7 +56,7 @@ void register_node_type_fn_input_vector() node_type_init(&ntype, fn_node_input_vector_init); node_type_storage( &ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage); - ntype.expand_in_mf_network = fn_node_vector_input_expand_in_mf_network; + ntype.build_multi_function = fn_node_vector_input_build_multi_function; ntype.draw_buttons = fn_node_input_vector_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc index a3c9f44b6a1..47ec9adf6bd 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_float.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc @@ -67,10 +67,11 @@ class RandomFloatFunction : public blender::fn::MultiFunction { } }; -static void fn_node_random_float_expand_in_mf_network( - blender::nodes::NodeMFNetworkBuilder &builder) +static void fn_node_random_float_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - builder.construct_and_set_matching_fn(); + static RandomFloatFunction fn; + builder.set_matching_fn(fn); } void register_node_type_fn_random_float() @@ -79,6 +80,6 @@ void register_node_type_fn_random_float() fn_node_type_base(&ntype, FN_NODE_RANDOM_FLOAT, "Random Float", 0, 0); node_type_socket_templates(&ntype, fn_node_random_float_in, fn_node_random_float_out); - ntype.expand_in_mf_network = fn_node_random_float_expand_in_mf_network; + ntype.build_multi_function = fn_node_random_float_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index ffa20579acc..a3bbca90731 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -19,7 +19,6 @@ #include "DEG_depsgraph_query.h" #include "NOD_geometry_exec.hh" -#include "NOD_type_callbacks.hh" #include "NOD_type_conversions.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/intern/node_multi_function.cc b/source/blender/nodes/intern/node_multi_function.cc new file mode 100644 index 00000000000..c91899ed8c2 --- /dev/null +++ b/source/blender/nodes/intern/node_multi_function.cc @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "NOD_multi_function.hh" + +namespace blender::nodes { + +NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope) +{ + for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) { + bNodeTree *btree = tree_ref->btree(); + for (const NodeRef *node : tree_ref->nodes()) { + bNode *bnode = node->bnode(); + if (bnode->typeinfo->build_multi_function == nullptr) { + continue; + } + NodeMultiFunctionBuilder builder{resource_scope, *bnode, *btree}; + bnode->typeinfo->build_multi_function(builder); + const MultiFunction *fn = builder.built_fn_; + if (fn != nullptr) { + map_.add_new(bnode, fn); + } + } + } +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 4be3fd2468b..528616eb23a 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -44,7 +44,6 @@ #include "MEM_guardedalloc.h" -#include "NOD_node_tree_multi_function.hh" #include "NOD_socket.h" #include "FN_cpp_type_make.hh" diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc deleted file mode 100644 index 7ab6495f733..00000000000 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ /dev/null @@ -1,409 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_node_tree_multi_function.hh" -#include "NOD_type_conversions.hh" - -#include "FN_multi_function_network_evaluation.hh" - -#include "BLI_color.hh" -#include "BLI_float2.hh" -#include "BLI_float3.hh" - -namespace blender::nodes { - -const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name) -{ - Vector input_types; - Vector output_types; - - for (const InputSocketRef *dsocket : dnode_->inputs()) { - if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->typeinfo()); - if (data_type.has_value()) { - input_types.append(*data_type); - } - } - } - for (const OutputSocketRef *dsocket : dnode_->outputs()) { - if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->typeinfo()); - if (data_type.has_value()) { - output_types.append(*data_type); - } - } - } - - const fn::MultiFunction &fn = this->construct_fn( - name, input_types, output_types); - return fn; -} - -static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &dnode) -{ - constexpr int stack_capacity = 10; - - Vector input_types; - Vector input_names; - Vector input_dsockets; - - for (const InputSocketRef *dsocket : dnode->inputs()) { - if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); - if (data_type.has_value()) { - input_types.append(*data_type); - input_names.append(dsocket->name()); - input_dsockets.append(dsocket); - } - } - } - - Vector output_types; - Vector output_names; - Vector output_dsockets; - - for (const OutputSocketRef *dsocket : dnode->outputs()) { - if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); - if (data_type.has_value()) { - output_types.append(*data_type); - output_names.append(dsocket->name()); - output_dsockets.append(dsocket); - } - } - } - - fn::MFDummyNode &dummy_node = common.network.add_dummy( - dnode->name(), input_types, output_types, input_names, output_names); - - common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs()); - common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs()); -} - -static bool has_data_sockets(const DNode &dnode) -{ - for (const InputSocketRef *socket : dnode->inputs()) { - if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { - return true; - } - } - for (const OutputSocketRef *socket : dnode->outputs()) { - if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { - return true; - } - } - return false; -} - -static void foreach_node_to_insert(CommonMFNetworkBuilderData &common, - FunctionRef callback) -{ - common.tree.foreach_node([&](const DNode dnode) { - if (dnode->is_group_node()) { - return; - } - /* Don't insert non-root group input/output nodes, because they will be inlined. */ - if (!dnode.context()->is_root()) { - if (dnode->is_group_input_node() || dnode->is_group_output_node()) { - return; - } - } - callback(dnode); - }); -} - -/** - * Expands all function nodes in the multi-function network. Nodes that don't have an expand - * function, but do have data sockets, will get corresponding dummy nodes. - */ -static void insert_nodes(CommonMFNetworkBuilderData &common) -{ - foreach_node_to_insert(common, [&](const DNode dnode) { - const bNodeType *node_type = dnode->typeinfo(); - if (node_type->expand_in_mf_network != nullptr) { - NodeMFNetworkBuilder builder{common, dnode}; - node_type->expand_in_mf_network(builder); - } - else if (has_data_sockets(dnode)) { - insert_dummy_node(common, dnode); - } - }); -} - -static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common, - fn::MFDataType type) -{ - const fn::MultiFunction *default_fn; - if (type.is_single()) { - default_fn = &common.scope.construct( - AT, type.single_type(), type.single_type().default_value()); - } - else { - default_fn = &common.scope.construct( - AT, fn::GSpan(type.vector_base_type())); - } - - fn::MFNode &node = common.network.add_function(*default_fn); - return node.output(0); -} - -static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common, - const DInputSocket &dsocket) -{ - BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo())); - - SocketMFNetworkBuilder builder{common, dsocket}; - socket_expand_in_mf_network(builder); - - fn::MFOutputSocket *built_socket = builder.built_socket(); - BLI_assert(built_socket != nullptr); - return built_socket; -} - -static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) -{ - foreach_node_to_insert(common, [&](const DNode dnode) { - for (const InputSocketRef *socket_ref : dnode->inputs()) { - const DInputSocket to_dsocket{dnode.context(), socket_ref}; - if (!to_dsocket->is_available()) { - continue; - } - if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) { - continue; - } - - Span to_sockets = common.network_map.lookup(to_dsocket); - BLI_assert(to_sockets.size() >= 1); - const fn::MFDataType to_type = to_sockets[0]->data_type(); - - Vector from_dsockets; - to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); }); - if (from_dsockets.size() > 1) { - fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(from_socket, *to_socket); - } - continue; - } - if (from_dsockets.is_empty()) { - /* The socket is not linked. Need to use the value of the socket itself. */ - fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*built_socket, *to_socket); - } - continue; - } - if (from_dsockets[0]->is_input()) { - DInputSocket from_dsocket{from_dsockets[0]}; - fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*built_socket, *to_socket); - } - continue; - } - DOutputSocket from_dsocket{from_dsockets[0]}; - fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket); - const fn::MFDataType from_type = from_socket->data_type(); - - if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = - get_implicit_type_conversions().get_conversion_multi_function(from_type, to_type); - if (conversion_fn != nullptr) { - fn::MFNode &node = common.network.add_function(*conversion_fn); - common.network.add_link(*from_socket, node.input(0)); - from_socket = &node.output(0); - } - else { - from_socket = &insert_default_value_for_type(common, to_type); - } - } - - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*from_socket, *to_socket); - } - } - }); -} - -/** - * Expands all function nodes contained in the given node tree within the given multi-function - * network. - * - * Returns a mapping between the original node tree and the generated nodes/sockets for further - * processing. - */ -MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, - const DerivedNodeTree &tree, - ResourceScope &scope) -{ - MFNetworkTreeMap network_map{tree, network}; - - CommonMFNetworkBuilderData common{scope, network, network_map, tree}; - - insert_nodes(common); - insert_links_and_unlinked_inputs(common); - - return network_map; -} - -/** - * A single node is allowed to expand into multiple nodes before evaluation. Depending on what - * nodes it expands to, it belongs a different type of the ones below. - */ -enum class NodeExpandType { - SingleFunctionNode, - MultipleFunctionNodes, - HasDummyNodes, -}; - -/** - * Checks how the given node expanded in the multi-function network. If it is only a single - * function node, the corresponding function is returned as well. - */ -static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map, - const DNode &dnode, - const fn::MultiFunction **r_single_function) -{ - const fn::MFFunctionNode *single_function_node = nullptr; - bool has_multiple_nodes = false; - bool has_dummy_nodes = false; - - auto check_mf_node = [&](fn::MFNode &mf_node) { - if (mf_node.is_function()) { - if (single_function_node == nullptr) { - single_function_node = &mf_node.as_function(); - } - if (&mf_node != single_function_node) { - has_multiple_nodes = true; - } - } - else { - BLI_assert(mf_node.is_dummy()); - has_dummy_nodes = true; - } - }; - - for (const InputSocketRef *dsocket : dnode->inputs()) { - if (dsocket->is_available()) { - for (fn::MFInputSocket *mf_input : - network_map.lookup(DInputSocket(dnode.context(), dsocket))) { - check_mf_node(mf_input->node()); - } - } - } - for (const OutputSocketRef *dsocket : dnode->outputs()) { - if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); - check_mf_node(mf_output.node()); - } - } - - if (has_dummy_nodes) { - return NodeExpandType::HasDummyNodes; - } - if (has_multiple_nodes) { - return NodeExpandType::MultipleFunctionNodes; - } - *r_single_function = &single_function_node->function(); - return NodeExpandType::SingleFunctionNode; -} - -static const fn::MultiFunction &create_function_for_node_that_expands_into_multiple( - const DNode &dnode, - fn::MFNetwork &network, - MFNetworkTreeMap &network_map, - ResourceScope &scope) -{ - Vector dummy_fn_inputs; - for (const InputSocketRef *dsocket : dnode->inputs()) { - if (dsocket->is_available()) { - MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo()); - fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type); - for (fn::MFInputSocket *mf_input : - network_map.lookup(DInputSocket(dnode.context(), dsocket))) { - network.add_link(fn_input, *mf_input); - dummy_fn_inputs.append(&fn_input); - } - } - } - Vector dummy_fn_outputs; - for (const OutputSocketRef *dsocket : dnode->outputs()) { - if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); - MFDataType data_type = mf_output.data_type(); - fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type); - network.add_link(mf_output, fn_output); - dummy_fn_outputs.append(&fn_output); - } - } - - fn::MFNetworkEvaluator &fn_evaluator = scope.construct( - __func__, std::move(dummy_fn_inputs), std::move(dummy_fn_outputs)); - return fn_evaluator; -} - -/** - * Returns a single multi-function for every node that supports it. This makes it easier to reuse - * the multi-function implementation of nodes in different contexts. - */ -MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope) -{ - /* Build a network that nodes can insert themselves into. However, the individual nodes are not - * connected. */ - fn::MFNetwork &network = scope.construct(__func__); - MFNetworkTreeMap network_map{tree, network}; - MultiFunctionByNode functions_by_node; - - CommonMFNetworkBuilderData common{scope, network, network_map, tree}; - - tree.foreach_node([&](DNode dnode) { - const bNodeType *node_type = dnode->typeinfo(); - if (node_type->expand_in_mf_network == nullptr) { - /* This node does not have a multi-function implementation. */ - return; - } - - NodeMFNetworkBuilder builder{common, dnode}; - node_type->expand_in_mf_network(builder); - - const fn::MultiFunction *single_function = nullptr; - const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function); - - switch (expand_type) { - case NodeExpandType::HasDummyNodes: { - /* Dummy nodes cannot be executed, so skip them. */ - break; - } - case NodeExpandType::SingleFunctionNode: { - /* This is the common case. Most nodes just expand to a single function. */ - functions_by_node.add_new(dnode, single_function); - break; - } - case NodeExpandType::MultipleFunctionNodes: { - /* If a node expanded into multiple functions, a new function has to be created that - * combines those. */ - const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple( - dnode, network, network_map, scope); - functions_by_node.add_new(dnode, &fn); - break; - } - } - }); - - return functions_by_node; -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/intern/type_callbacks.cc b/source/blender/nodes/intern/type_callbacks.cc deleted file mode 100644 index 881a02c92e9..00000000000 --- a/source/blender/nodes/intern/type_callbacks.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_node_tree_multi_function.hh" -#include "NOD_type_callbacks.hh" - -namespace blender::nodes { - -std::optional socket_mf_type_get(const bNodeSocketType &stype) -{ - const CPPType *cpp_type = stype.get_base_cpp_type ? stype.get_base_cpp_type() : nullptr; - if (cpp_type != nullptr) { - return MFDataType::ForSingle(*cpp_type); - } - return {}; -} - -bool socket_is_mf_data_socket(const bNodeSocketType &stype) -{ - if (!socket_mf_type_get(stype).has_value()) { - return false; - } - if (stype.expand_in_mf_network == nullptr && stype.get_base_cpp_value == nullptr) { - return false; - } - return true; -} - -void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder) -{ - bNodeSocket &socket = builder.bsocket(); - if (socket.typeinfo->expand_in_mf_network != nullptr) { - socket.typeinfo->expand_in_mf_network(builder); - } - else if (socket.typeinfo->get_base_cpp_value != nullptr) { - const CPPType &type = *socket.typeinfo->get_base_cpp_type(); - void *buffer = builder.resource_scope().linear_allocator().allocate(type.size(), - type.alignment()); - socket.typeinfo->get_base_cpp_value(socket, buffer); - builder.set_constant_value(type, buffer); - } - else { - BLI_assert_unreachable(); - } -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h index dc44f0fa98f..a75354d3381 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.h @@ -72,7 +72,7 @@ #ifdef __cplusplus # include "FN_multi_function_builder.hh" -# include "NOD_node_tree_multi_function.hh" +# include "NOD_multi_function.hh" # include "BLI_color.hh" # include "BLI_float3.hh" diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index 4f77421cfe0..f105f8bcaf9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -51,7 +51,7 @@ static int gpu_shader_clamp(GPUMaterial *mat, GPU_stack_link(mat, node, "clamp_range", in, out); } -static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { static blender::fn::CustomMF_SI_SI_SI_SO minmax_fn{ "Clamp (Min Max)", @@ -65,7 +65,7 @@ static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuil return clamp_f(value, b, a); }}; - int clamp_type = builder.bnode().custom1; + int clamp_type = builder.node().custom1; if (clamp_type == NODE_CLAMP_MINMAX) { builder.set_matching_fn(minmax_fn); } @@ -82,7 +82,7 @@ void register_node_type_sh_clamp(void) node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out); node_type_init(&ntype, node_shader_init_clamp); node_type_gpu(&ntype, gpu_shader_clamp); - ntype.expand_in_mf_network = sh_node_clamp_expand_in_mf_network; + ntype.build_multi_function = sh_node_clamp_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index f1d5040a292..df075d6e973 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -143,9 +143,10 @@ class CurveVecFunction : public blender::fn::MultiFunction { } }; -static void sh_node_curve_vec_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_curve_vec_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -162,7 +163,7 @@ void register_node_type_sh_curve_vec(void) node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec); node_type_gpu(&ntype, gpu_shader_curve_vec); - ntype.expand_in_mf_network = sh_node_curve_vec_expand_in_mf_network; + ntype.build_multi_function = sh_node_curve_vec_build_multi_function; nodeRegisterType(&ntype); } @@ -317,9 +318,10 @@ class CurveRGBFunction : public blender::fn::MultiFunction { } }; -static void sh_node_curve_rgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_curve_rgb_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -336,7 +338,7 @@ void register_node_type_sh_curve_rgb(void) node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb); node_type_gpu(&ntype, gpu_shader_curve_rgb); - ntype.expand_in_mf_network = sh_node_curve_rgb_expand_in_mf_network; + ntype.build_multi_function = sh_node_curve_rgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index ad7abd9d491..e4739e2864d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -261,9 +261,10 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction { } }; -static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_map_range_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); bool clamp = bnode.custom1 != 0; int interpolation_type = bnode.custom2; @@ -301,7 +302,6 @@ static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetwork break; } default: - builder.set_not_implemented(); break; } } @@ -315,7 +315,7 @@ void register_node_type_sh_map_range(void) node_type_init(&ntype, node_shader_init_map_range); node_type_update(&ntype, node_shader_update_map_range); node_type_gpu(&ntype, gpu_shader_map_range); - ntype.expand_in_mf_network = sh_node_map_range_expand_in_mf_network; + ntype.build_multi_function = sh_node_map_range_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 7a846031456..c30f2948ab1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -69,11 +69,9 @@ static int gpu_shader_math(GPUMaterial *mat, return 0; } -static const blender::fn::MultiFunction &get_base_multi_function( - blender::nodes::NodeMFNetworkBuilder &builder) +static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) { - const int mode = builder.bnode().custom1; - + const int mode = node.custom1; const blender::fn::MultiFunction *base_fn = nullptr; blender::nodes::try_dispatch_float_math_fl_to_fl( @@ -82,7 +80,7 @@ static const blender::fn::MultiFunction &get_base_multi_function( base_fn = &fn; }); if (base_fn != nullptr) { - return *base_fn; + return base_fn; } blender::nodes::try_dispatch_float_math_fl_fl_to_fl( @@ -92,7 +90,7 @@ static const blender::fn::MultiFunction &get_base_multi_function( base_fn = &fn; }); if (base_fn != nullptr) { - return *base_fn; + return base_fn; } blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl( @@ -102,36 +100,51 @@ static const blender::fn::MultiFunction &get_base_multi_function( base_fn = &fn; }); if (base_fn != nullptr) { - return *base_fn; + return base_fn; } - return builder.get_not_implemented_fn(); + return nullptr; } -static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) -{ - const blender::fn::MultiFunction &base_function = get_base_multi_function(builder); +class ClampWrapperFunction : public blender::fn::MultiFunction { + private: + const blender::fn::MultiFunction &fn_; - const blender::nodes::DNode &dnode = builder.dnode(); - blender::fn::MFNetwork &network = builder.network(); - blender::fn::MFFunctionNode &base_node = network.add_function(base_function); + public: + ClampWrapperFunction(const blender::fn::MultiFunction &fn) : fn_(fn) + { + this->set_signature(&fn.signature()); + } - builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs()); + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext context) const override + { + fn_.call(mask, params, context); + + /* Assumes the output parameter is the last one. */ + const int output_param_index = this->param_amount() - 1; + /* This has actually been initialized in the call above. */ + blender::MutableSpan results = params.uninitialized_single_output( + output_param_index); + + for (const int i : mask) { + float &value = results[i]; + CLAMP(value, 0.0f, 1.0f); + } + } +}; + +static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) +{ + const blender::fn::MultiFunction *base_function = get_base_multi_function(builder.node()); - const bool clamp_output = builder.bnode().custom2 != 0; + const bool clamp_output = builder.node().custom2 != 0; if (clamp_output) { - static blender::fn::CustomMF_SI_SO clamp_fn{"Clamp", [](float value) { - CLAMP(value, 0.0f, 1.0f); - return value; - }}; - blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn); - network.add_link(base_node.output(0), clamp_node.input(0)); - builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), - clamp_node.output(0)); + builder.construct_and_set_matching_fn(*base_function); } else { - builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), - base_node.output(0)); + builder.set_matching_fn(base_function); } } @@ -144,7 +157,7 @@ void register_node_type_sh_math(void) node_type_label(&ntype, node_math_label); node_type_gpu(&ntype, gpu_shader_math); node_type_update(&ntype, node_math_update); - ntype.expand_in_mf_network = sh_node_math_expand_in_mf_network; + ntype.build_multi_function = sh_node_math_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc index 47011caeeb6..ade35a40366 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc @@ -174,9 +174,9 @@ class MixRGBFunction : public blender::fn::MultiFunction { } }; -static void sh_node_mix_rgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &node = builder.bnode(); + bNode &node = builder.node(); bool clamp = node.custom2 & SHD_MIXRGB_CLAMP; int mix_type = node.custom1; builder.construct_and_set_matching_fn(clamp, mix_type); @@ -191,7 +191,7 @@ void register_node_type_sh_mix_rgb(void) node_type_label(&ntype, node_blend_label); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb); node_type_gpu(&ntype, gpu_shader_mix_rgb); - ntype.expand_in_mf_network = sh_node_mix_rgb_expand_in_mf_network; + ntype.build_multi_function = sh_node_mix_rgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc index a7239154633..2779fc6bf68 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc @@ -96,7 +96,7 @@ class SeparateRGBFunction : public blender::fn::MultiFunction { } }; -static void sh_node_seprgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { static SeparateRGBFunction fn; builder.set_matching_fn(fn); @@ -110,7 +110,7 @@ void register_node_type_sh_seprgb(void) node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb); node_type_gpu(&ntype, gpu_shader_seprgb); - ntype.expand_in_mf_network = sh_node_seprgb_expand_in_mf_network; + ntype.build_multi_function = sh_node_seprgb_build_multi_function; nodeRegisterType(&ntype); } @@ -153,7 +153,7 @@ static int gpu_shader_combrgb(GPUMaterial *mat, return GPU_stack_link(mat, node, "combine_rgb", in, out); } -static void sh_node_combrgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Combine RGB", @@ -169,7 +169,7 @@ void register_node_type_sh_combrgb(void) node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb); node_type_gpu(&ntype, gpu_shader_combrgb); - ntype.expand_in_mf_network = sh_node_combrgb_expand_in_mf_network; + ntype.build_multi_function = sh_node_combrgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc index efa9581c414..1fd794cdd0a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc @@ -81,7 +81,7 @@ class MF_SeparateXYZ : public blender::fn::MultiFunction { } }; -static void sh_node_sepxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { static MF_SeparateXYZ separate_fn; builder.set_matching_fn(separate_fn); @@ -94,7 +94,7 @@ void register_node_type_sh_sepxyz(void) sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out); node_type_gpu(&ntype, gpu_shader_sepxyz); - ntype.expand_in_mf_network = sh_node_sepxyz_expand_in_mf_network; + ntype.build_multi_function = sh_node_sepxyz_build_multi_function; nodeRegisterType(&ntype); } @@ -120,7 +120,7 @@ static int gpu_shader_combxyz(GPUMaterial *mat, return GPU_stack_link(mat, node, "combine_xyz", in, out); } -static void sh_node_combxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Combine Vector", [](float x, float y, float z) { return blender::float3(x, y, z); }}; @@ -134,7 +134,7 @@ void register_node_type_sh_combxyz(void) sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out); node_type_gpu(&ntype, gpu_shader_combxyz); - ntype.expand_in_mf_network = sh_node_combxyz_expand_in_mf_network; + ntype.build_multi_function = sh_node_combxyz_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc index 5b2eb300aac..1bc42ab0cc6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc @@ -163,9 +163,10 @@ class ColorBandFunction : public blender::fn::MultiFunction { } }; -static void sh_node_valtorgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_valtorgb_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.bnode(); + bNode &bnode = builder.node(); const ColorBand *color_band = (const ColorBand *)bnode.storage; builder.construct_and_set_matching_fn(*color_band); } @@ -181,7 +182,7 @@ void register_node_type_sh_valtorgb(void) node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb); node_type_gpu(&ntype, gpu_shader_valtorgb); - ntype.expand_in_mf_network = sh_node_valtorgb_expand_in_mf_network; + ntype.build_multi_function = sh_node_valtorgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 495c8d12824..602d5a1cf56 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -39,9 +39,9 @@ static int gpu_shader_value(GPUMaterial *mat, return GPU_stack_link(mat, node, "set_value", in, out, link); } -static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) { - const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket(); + const bNodeSocket *bsocket = (bNodeSocket *)builder.node().outputs.first; const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value; builder.construct_and_set_matching_fn>(value->value); } @@ -53,7 +53,7 @@ void register_node_type_sh_value(void) sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0); node_type_socket_templates(&ntype, nullptr, sh_node_value_out); node_type_gpu(&ntype, gpu_shader_value); - ntype.expand_in_mf_network = sh_node_value_expand_in_mf_network; + ntype.build_multi_function = sh_node_value_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 419a11201aa..4424db6aed1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -183,12 +183,11 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node } } -static const blender::fn::MultiFunction &get_multi_function( - blender::nodes::NodeMFNetworkBuilder &builder) +static const blender::fn::MultiFunction *get_multi_function(bNode &node) { using blender::float3; - NodeVectorMathOperation operation = NodeVectorMathOperation(builder.bnode().custom1); + NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1); const blender::fn::MultiFunction *multi_fn = nullptr; @@ -199,7 +198,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( @@ -209,7 +208,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( @@ -219,7 +218,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( @@ -229,7 +228,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( @@ -239,7 +238,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_to_fl3( @@ -248,7 +247,7 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } blender::nodes::try_dispatch_float_math_fl3_to_fl( @@ -257,15 +256,16 @@ static const blender::fn::MultiFunction &get_multi_function( multi_fn = &fn; }); if (multi_fn != nullptr) { - return *multi_fn; + return multi_fn; } - return builder.get_not_implemented_fn(); + return nullptr; } -static void sh_node_vector_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_vector_math_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - const blender::fn::MultiFunction &fn = get_multi_function(builder); + const blender::fn::MultiFunction *fn = get_multi_function(builder.node()); builder.set_matching_fn(fn); } @@ -278,7 +278,7 @@ void register_node_type_sh_vect_math(void) node_type_label(&ntype, node_vector_math_label); node_type_gpu(&ntype, gpu_shader_vector_math); node_type_update(&ntype, node_shader_update_vector_math); - ntype.expand_in_mf_network = sh_node_vector_math_expand_in_mf_network; + ntype.build_multi_function = sh_node_vector_math_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 3b2c2fa5a03..bc51b7e29ea 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -100,11 +100,10 @@ static float3 sh_node_vector_rotate_euler(const float3 vector, return result + center; } -static const blender::fn::MultiFunction &get_multi_function( - blender::nodes::NodeMFNetworkBuilder &builder) +static const blender::fn::MultiFunction *get_multi_function(bNode &node) { - bool invert = builder.bnode().custom2; - const int mode = builder.bnode().custom1; + bool invert = node.custom2; + const int mode = node.custom1; switch (mode) { case NODE_VECTOR_ROTATE_TYPE_AXIS: { @@ -113,13 +112,13 @@ static const blender::fn::MultiFunction &get_multi_function( "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, -angle); }}; - return fn; + return &fn; } static blender::fn::CustomMF_SI_SI_SI_SI_SO fn{ "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, angle); }}; - return fn; + return &fn; } case NODE_VECTOR_ROTATE_TYPE_AXIS_X: { float3 axis = float3(1.0f, 0.0f, 0.0f); @@ -128,13 +127,13 @@ static const blender::fn::MultiFunction &get_multi_function( "Rotate X-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, -angle); }}; - return fn; + return &fn; } static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Rotate X-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, angle); }}; - return fn; + return &fn; } case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: { float3 axis = float3(0.0f, 1.0f, 0.0f); @@ -143,13 +142,13 @@ static const blender::fn::MultiFunction &get_multi_function( "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, -angle); }}; - return fn; + return &fn; } static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, angle); }}; - return fn; + return &fn; } case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: { float3 axis = float3(0.0f, 0.0f, 1.0f); @@ -158,13 +157,13 @@ static const blender::fn::MultiFunction &get_multi_function( "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, -angle); }}; - return fn; + return &fn; } static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { return sh_node_vector_rotate_around_axis(in, center, axis, angle); }}; - return fn; + return &fn; } case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: { if (invert) { @@ -172,24 +171,24 @@ static const blender::fn::MultiFunction &get_multi_function( "Rotate Euler", [](float3 in, float3 center, float3 rotation) { return sh_node_vector_rotate_euler(in, center, rotation, true); }}; - return fn; + return &fn; } static blender::fn::CustomMF_SI_SI_SI_SO fn{ "Rotate Euler", [](float3 in, float3 center, float3 rotation) { return sh_node_vector_rotate_euler(in, center, rotation, false); }}; - return fn; + return &fn; } default: BLI_assert_unreachable(); - return builder.get_not_implemented_fn(); + return nullptr; } } -static void sh_node_vector_rotate_expand_in_mf_network( - blender::nodes::NodeMFNetworkBuilder &builder) +static void sh_node_vector_rotate_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) { - const blender::fn::MultiFunction &fn = get_multi_function(builder); + const blender::fn::MultiFunction *fn = get_multi_function(builder.node()); builder.set_matching_fn(fn); } @@ -211,7 +210,7 @@ void register_node_type_sh_vector_rotate(void) node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); node_type_gpu(&ntype, gpu_shader_vector_rotate); node_type_update(&ntype, node_shader_update_vector_rotate); - ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network; + ntype.build_multi_function = sh_node_vector_rotate_build_multi_function; nodeRegisterType(&ntype); } -- cgit v1.2.3 From ef502127ddc0f5a06e76cb2f634655b8e9c8f740 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 20 Aug 2021 08:40:13 -0300 Subject: Fix T90795: Moving keys in Grease Pencil Dopesheet crashes Blender `td->loc` is referenced but not initialized. --- source/blender/editors/transform/transform_convert_action.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index 8a3b254be5c..a5565b5fb88 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -241,16 +241,15 @@ static int GPLayerToTransData(TransData *td, for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) { if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { - /* memory is calloc'ed, so that should zero everything nicely for us */ - td->val = &tfd->val; - td->ival = (float)gpf->framenum; + tfd->val = (float)gpf->framenum; + tfd->sdata = &gpf->framenum; + + td->val = td->loc = &tfd->val; /* XXX: It's not a 3d array. */ + td->ival = td->iloc[0] = (float)gpf->framenum; td->center[0] = td->ival; td->center[1] = ypos; - tfd->val = (float)gpf->framenum; - tfd->sdata = &gpf->framenum; - /* Advance `td` now. */ td++; tfd++; -- cgit v1.2.3 From 9bfc47c9334bc4fbecbe7871fff9af4cc46c8832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 20 Aug 2021 14:29:05 +0200 Subject: Alembic Procedural: basic cache control settings This adds a setting to enable data caching, and another one to set the maximum cache size in megabytes. When caching is enabled we load the data for the entire animation in memory, as we already do, however, if the data exceeds the memory limit, render is aborted. When caching is disabled, we simply load the data for the current frame in memory. Ref D10197 Reviewed By: brecht Differential Revision: https://developer.blender.org/D11163 --- source/blender/editors/interface/interface_templates.c | 15 +++++++++++++++ source/blender/makesdna/DNA_cachefile_defaults.h | 2 ++ source/blender/makesdna/DNA_cachefile_types.h | 10 +++++++++- source/blender/makesrna/intern/rna_cachefile.c | 17 +++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 351b73c320b..cdb35d19855 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6489,6 +6489,17 @@ void uiTemplateCacheFile(uiLayout *layout, uiLayoutSetActive(row, engine_supports_procedural); uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE); + const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural"); + const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch"); + + row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, use_render_procedural); + uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE); + + sub = uiLayoutRow(layout, false); + uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural); + uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE); + row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); sub = uiLayoutRow(row, true); uiLayoutSetPropDecorate(sub, false); @@ -6510,6 +6521,10 @@ void uiTemplateCacheFile(uiLayout *layout, uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE); uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE); + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, engine_supports_procedural && use_render_procedural); + uiItemR(row, &fileptr, "default_radius", 0, NULL, ICON_NONE); + /* TODO: unused for now, so no need to expose. */ #if 0 row = uiLayoutRow(layout, false); diff --git a/source/blender/makesdna/DNA_cachefile_defaults.h b/source/blender/makesdna/DNA_cachefile_defaults.h index 521b72567d4..74fbe5012ab 100644 --- a/source/blender/makesdna/DNA_cachefile_defaults.h +++ b/source/blender/makesdna/DNA_cachefile_defaults.h @@ -40,6 +40,8 @@ .handle = NULL, \ .handle_filepath[0] = '\0', \ .handle_readers = NULL, \ + .use_prefetch = 1, \ + .prefetch_cache_size = 4096, \ } /** \} */ diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index ae4ade49be1..0f4c53a6e7e 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -101,7 +101,15 @@ typedef struct CacheFile { */ char use_render_procedural; - char _pad1[7]; + char _pad1[3]; + + /** Enable data prefetching when using the Cycles Procedural. */ + char use_prefetch; + + /** Size in megabytes for the prefetch cache used by the Cycles Procedural. */ + int prefetch_cache_size; + + char _pad2[7]; char velocity_unit; /* Name of the velocity property in the archive. */ diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index cb0a490417d..74d924b8937 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -150,6 +150,23 @@ static void rna_def_cachefile(BlenderRNA *brna) "determine which file to use in a file sequence"); RNA_def_property_update(prop, 0, "rna_CacheFile_update"); + /* ----------------- Cache controls ----------------- */ + + prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_ui_text( + prop, + "Use Prefetch", + "When enabled, the Cycles Procedural will preload animation data for faster updates"); + RNA_def_property_update(prop, 0, "rna_CacheFile_update"); + + prop = RNA_def_property(srna, "prefetch_cache_size", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_text( + prop, + "Prefetch Cache Size", + "Memory usage limit in megabytes for the Cycles Procedural cache, if the data does not " + "fit within the limit, rendering is aborted"); + RNA_def_property_update(prop, 0, "rna_CacheFile_update"); + /* ----------------- Axis Conversion ----------------- */ prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE); -- cgit v1.2.3 From 6a404bc633586a96d635e2e3bf2e207f87ab3785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 20 Aug 2021 14:48:47 +0200 Subject: Cleanup, remove extra code from previous commit This got accidentally introduced while revising dependencies between patches for this feature, did not notice until it was too late. --- source/blender/editors/interface/interface_templates.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index cdb35d19855..0e5a6a79137 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6521,10 +6521,6 @@ void uiTemplateCacheFile(uiLayout *layout, uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE); uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, engine_supports_procedural && use_render_procedural); - uiItemR(row, &fileptr, "default_radius", 0, NULL, ICON_NONE); - /* TODO: unused for now, so no need to expose. */ #if 0 row = uiLayoutRow(layout, false); -- cgit v1.2.3 From 1b5f17b86771faa87d36ff12183aa6dbb5c1e9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 20 Aug 2021 15:00:58 +0200 Subject: Cleanup, use BKE_scene_uses_cycles_experimental_features --- source/blender/modifiers/intern/MOD_subsurf.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index ce427281db3..db0b769684e 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -358,13 +358,8 @@ static bool get_show_adaptive_options(const bContext *C, Panel *panel) /* Don't show adaptive options if the cycles experimental feature set is disabled. */ Scene *scene = CTX_data_scene(C); - PointerRNA scene_ptr; - RNA_id_pointer_create(&scene->id, &scene_ptr); - if (BKE_scene_uses_cycles(scene)) { - PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles"); - if (RNA_enum_get(&cycles_ptr, "feature_set") != 1) { /* EXPERIMENTAL */ - return false; - } + if (!BKE_scene_uses_cycles_experimental_features(scene)) { + return false; } return true; -- cgit v1.2.3 From b6a1bf757d9f0675f0fb5f21a72ff4ee31f8d6d9 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Fri, 20 Aug 2021 14:54:46 -0400 Subject: DocPy: Cleanup missing newline resulting in wrong html generation --- source/blender/python/intern/bpy_app_icons.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/intern/bpy_app_icons.c b/source/blender/python/intern/bpy_app_icons.c index 7cca3ae4700..acd809fb8d5 100644 --- a/source/blender/python/intern/bpy_app_icons.c +++ b/source/blender/python/intern/bpy_app_icons.c @@ -35,7 +35,7 @@ /* We may want to load direct from file. */ PyDoc_STRVAR( bpy_app_icons_new_triangles_doc, - ".. function:: new_triangles(range, coords, colors)" + ".. function:: new_triangles(range, coords, colors)\n" "\n" " Create a new icon from triangle geometry.\n" "\n" @@ -91,7 +91,7 @@ static PyObject *bpy_app_icons_new_triangles(PyObject *UNUSED(self), PyObject *a } PyDoc_STRVAR(bpy_app_icons_new_triangles_from_file_doc, - ".. function:: new_triangles_from_file(filename)" + ".. function:: new_triangles_from_file(filename)\n" "\n" " Create a new icon from triangle geometry.\n" "\n" @@ -122,7 +122,7 @@ static PyObject *bpy_app_icons_new_triangles_from_file(PyObject *UNUSED(self), } PyDoc_STRVAR(bpy_app_icons_release_doc, - ".. function:: release(icon_id)" + ".. function:: release(icon_id)\n" "\n" " Release the icon.\n"); static PyObject *bpy_app_icons_release(PyObject *UNUSED(self), PyObject *args, PyObject *kw) -- cgit v1.2.3 From 0d7aab2375e6bb06e89dad851550b283a1ff805c Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 20 Aug 2021 17:48:42 -0700 Subject: Refactor: BLF Kerning Cache After Use Optimization of font kerning by only caching kerning values after a pair is encountered. Also saves unscaled values so they don't have to be rebuilt between font size changes. See D12274 for more details and speed comparison. Differential Revision: https://developer.blender.org/D12274 Reviewed by Campbell Barton --- source/blender/blenfont/intern/blf.c | 1 - source/blender/blenfont/intern/blf_font.c | 96 +++++++++++++--------- source/blender/blenfont/intern/blf_glyph.c | 50 ----------- source/blender/blenfont/intern/blf_internal.h | 4 - .../blender/blenfont/intern/blf_internal_types.h | 9 +- 5 files changed, 62 insertions(+), 98 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 9168e7aa19c..2f9eb0753ac 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -108,7 +108,6 @@ void BLF_cache_clear(void) FontBLF *font = global_font[i]; if (font) { blf_glyph_cache_clear(font); - blf_kerning_cache_clear(font); } } } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 00d3cfb09eb..02847b74df1 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -308,17 +308,6 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) blf_glyph_cache_release(font); } -static void blf_font_ensure_ascii_kerning(FontBLF *font, GlyphCacheBLF *gc) -{ - if (font->kerning_cache || !FT_HAS_KERNING(font->face)) { - return; - } - font->kerning_cache = blf_kerning_cache_find(font); - if (!font->kerning_cache) { - font->kerning_cache = blf_kerning_cache_new(font, gc); - } -} - /* Fast path for runs of ASCII characters. Given that common UTF-8 * input will consist of an overwhelming majority of ASCII * characters. @@ -348,6 +337,31 @@ BLI_INLINE GlyphBLF *blf_utf8_next_fast( return g; } +/* Convert a FreeType 26.6 value representing an unscaled design size to pixels. + * This is an exact copy of the scaling done inside FT_Get_Kerning when called + * with FT_KERNING_DEFAULT, including arbitrary resizing for small fonts. + */ +static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) +{ + /* Scale value by font size using integer-optimized multiplication. */ + FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale); + + /* FreeType states that this '25' has been determined heuristically. */ + if (font->face->size->metrics.x_ppem < 25) { + scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25); + } + + /* Copies of internal FreeType macros needed here. */ +#define FT_PIX_FLOOR(x) ((x) & ~FT_TYPEOF(x) 63) +#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32) + + /* Round to even 64ths, then divide by 64. */ + return FT_PIX_ROUND(scaled) >> 6; + +#undef FT_PIX_FLOOR +#undef FT_PIX_ROUND +} + BLI_INLINE void blf_kerning_step_fast(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g, @@ -355,18 +369,28 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, const uint c, int *pen_x_p) { - /* `blf_font_ensure_ascii_kerning(font, gc);` must be called before this function. */ - BLI_assert(font->kerning_cache != NULL || !FT_HAS_KERNING(font->face)); + if (FT_HAS_KERNING(font->face) && g_prev != NULL) { + FT_Vector delta = {KERNING_ENTRY_UNSET}; - if (g_prev != NULL && FT_HAS_KERNING(font->face)) { + /* Get unscaled kerning value from our cache if ASCII. */ if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - *pen_x_p += font->kerning_cache->ascii_table[c][c_prev]; + delta.x = font->kerning_cache->ascii_table[c][c_prev]; } - else { - FT_Vector delta; - if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_DEFAULT, &delta) == 0) { - *pen_x_p += (int)delta.x >> 6; - } + + /* If not ASCII or not found in cache, ask FreeType for kerning. */ + if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) { + /* Note that this function sets delta values to zero on any error. */ + FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta); + } + + /* If ASCII we save this value to our cache for quicker access next time. */ + if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { + font->kerning_cache->ascii_table[c][c_prev] = delta.x; + } + + if (delta.x != 0) { + /* Convert unscaled design units to pixels and move pen. */ + *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x); } } } @@ -388,8 +412,6 @@ static void blf_font_draw_ex(FontBLF *font, return; } - blf_font_ensure_ascii_kerning(font, gc); - blf_batch_draw_begin(font); while ((i < len) && str[i]) { @@ -435,8 +457,6 @@ static void blf_font_draw_ascii_ex( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_kerning(font, gc); - blf_batch_draw_begin(font); while ((c = *(str++)) && len--) { @@ -536,8 +556,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, int chx, chy; int y, x; - blf_font_ensure_ascii_kerning(font, gc); - /* another buffer specific call for color conversion */ while ((i < len) && str[i]) { @@ -694,8 +712,6 @@ size_t blf_font_width_to_strlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - blf_font_ensure_ascii_kerning(font, gc); - for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i]; i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { g = blf_utf8_next_fast(font, gc, str, &i, &c); @@ -725,8 +741,6 @@ size_t blf_font_width_to_rstrlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - blf_font_ensure_ascii_kerning(font, gc); - i = BLI_strnlen(str, len); s = BLI_str_find_prev_char_utf8(str, &str[i]); i = (size_t)((s != NULL) ? s - str : 0); @@ -778,8 +792,6 @@ static void blf_font_boundbox_ex(FontBLF *font, box->ymin = 32000.0f; box->ymax = -32000.0f; - blf_font_ensure_ascii_kerning(font, gc); - while ((i < len) && str[i]) { g = blf_utf8_next_fast(font, gc, str, &i, &c); @@ -869,8 +881,6 @@ static void blf_font_wrap_apply(FontBLF *font, GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_ensure_ascii_kerning(font, gc); - struct WordWrapVars { int wrap_width; size_t start, last[2]; @@ -1123,8 +1133,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, return; } - blf_font_ensure_ascii_kerning(font, gc); - while ((i < len) && str[i]) { i_curr = i; g = blf_utf8_next_fast(font, gc, str, &i, &c); @@ -1205,7 +1213,9 @@ void blf_font_free(FontBLF *font) blf_glyph_cache_free(gc); } - blf_kerning_cache_clear(font); + if (font->kerning_cache) { + MEM_freeN(font->kerning_cache); + } FT_Done_Face(font->face); if (font->filename) { @@ -1246,7 +1256,6 @@ static void blf_font_fill(FontBLF *font) font->dpi = 0; font->size = 0; BLI_listbase_clear(&font->cache); - BLI_listbase_clear(&font->kerning_caches); font->kerning_cache = NULL; #if BLF_BLUR_ENABLE font->blur = 0; @@ -1307,6 +1316,17 @@ FontBLF *blf_font_new(const char *name, const char *filename) font->name = BLI_strdup(name); font->filename = BLI_strdup(filename); blf_font_fill(font); + + if (FT_HAS_KERNING(font->face)) { + /* Create kerning cache table and fill with value indicating "unset". */ + font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__); + for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { + for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { + font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET; + } + } + } + return font; } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 5fb69251466..6cdf5fc5996 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -55,56 +55,6 @@ #include "BLI_math_vector.h" #include "BLI_strict_flags.h" -KerningCacheBLF *blf_kerning_cache_find(FontBLF *font) -{ - return (KerningCacheBLF *)font->kerning_caches.first; -} - -/* Create a new glyph cache for the current kerning mode. */ -KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc) -{ - KerningCacheBLF *kc = MEM_mallocN(sizeof(KerningCacheBLF), __func__); - kc->next = NULL; - kc->prev = NULL; - - GlyphBLF *g_table[KERNING_CACHE_TABLE_SIZE]; - for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { - GlyphBLF *g = blf_glyph_search(gc, i); - if (UNLIKELY(g == NULL)) { - FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); - g = blf_glyph_add(font, gc, glyph_index, i); - } - g_table[i] = g; - } - - memset(kc->ascii_table, 0, sizeof(kc->ascii_table)); - for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { - GlyphBLF *g = g_table[i]; - if (g == NULL) { - continue; - } - for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) { - GlyphBLF *g_prev = g_table[j]; - if (g_prev == NULL) { - continue; - } - FT_Vector delta; - if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_DEFAULT, &delta) == 0) { - kc->ascii_table[i][j] = (int)delta.x >> 6; - } - } - } - - BLI_addhead(&font->kerning_caches, kc); - return kc; -} - -void blf_kerning_cache_clear(FontBLF *font) -{ - font->kerning_cache = NULL; - BLI_freelistN(&font->kerning_caches); -} - GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) { GlyphCacheBLF *p; diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 35a6d019eac..ab2a26b1e06 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -121,10 +121,6 @@ int blf_font_count_missing_chars(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -struct KerningCacheBLF *blf_kerning_cache_find(struct FontBLF *font); -struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font, struct GlyphCacheBLF *gc); -void blf_kerning_cache_clear(struct FontBLF *font); - struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index caa10b2b125..38d7d7b6e21 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -34,6 +34,9 @@ /* Number of characters in KerningCacheBLF.table. */ #define KERNING_CACHE_TABLE_SIZE 128 +/* A value in the kerning cache that indicates it is not yet set. */ +#define KERNING_ENTRY_UNSET INT_MAX + typedef struct BatchBLF { struct FontBLF *font; /* can only batch glyph from the same font */ struct GPUBatch *batch; @@ -50,7 +53,6 @@ typedef struct BatchBLF { extern BatchBLF g_batch; typedef struct KerningCacheBLF { - struct KerningCacheBLF *next, *prev; /** * Cache a ascii glyph pairs. Only store the x offset we are interested in, * instead of the full #FT_Vector since it's not used for drawing at the moment. @@ -223,10 +225,7 @@ typedef struct FontBLF { */ ListBase cache; - /* list of kerning cache for this font. */ - ListBase kerning_caches; - - /* current kerning cache for this font and kerning mode. */ + /* Cache of unscaled kerning values. Will be NULL if font does not have kerning. */ KerningCacheBLF *kerning_cache; /* freetype2 lib handle. */ -- cgit v1.2.3 From aed5a27755531aeef1e6f7a19dbde066cd9f2aba Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Aug 2021 13:22:47 +1000 Subject: Correct build error from 0d7aab2375e6bb06e89dad851550b283a1ff805c --- source/blender/blenfont/intern/blf_font.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 02847b74df1..436c4712e25 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -352,11 +352,11 @@ static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) } /* Copies of internal FreeType macros needed here. */ -#define FT_PIX_FLOOR(x) ((x) & ~FT_TYPEOF(x) 63) +#define FT_PIX_FLOOR(x) ((x) & ~63) #define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32) /* Round to even 64ths, then divide by 64. */ - return FT_PIX_ROUND(scaled) >> 6; + return (int)FT_PIX_ROUND(scaled) >> 6; #undef FT_PIX_FLOOR #undef FT_PIX_ROUND @@ -385,7 +385,7 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, /* If ASCII we save this value to our cache for quicker access next time. */ if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - font->kerning_cache->ascii_table[c][c_prev] = delta.x; + font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x; } if (delta.x != 0) { -- cgit v1.2.3 From c671bfe14e8d8c72a146b74e4dcc1c8ee7ab5bb4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Aug 2021 13:23:39 +1000 Subject: Cleanup: spelling in comments & minor cleanup Also hyphenate 'mouse-move' use doxy sections in render_update.c & move function comment from the header to the source. --- source/blender/blenkernel/BKE_cachefile.h | 5 ---- source/blender/blenkernel/intern/cachefile.c | 8 +++++- source/blender/draw/engines/eevee/eevee_lookdev.c | 2 +- .../blender/editors/gpencil/gpencil_interpolate.c | 4 +-- source/blender/editors/gpencil/gpencil_primitive.c | 4 +-- .../blender/editors/interface/interface_handlers.c | 8 +++--- source/blender/editors/mesh/editmesh_tools.c | 2 +- source/blender/editors/physics/particle_edit.c | 2 +- source/blender/editors/render/render_update.c | 32 ++++++++++++++-------- .../editors/space_view3d/view3d_gizmo_ruler.c | 4 ++- .../editors/transform/transform_convert_armature.c | 4 +-- .../editors/transform/transform_convert_object.c | 2 +- .../editors/transform/transform_snap_animation.c | 4 +-- source/blender/io/collada/collada_internal.cpp | 2 +- .../blender/windowmanager/intern/wm_event_system.c | 4 +-- 15 files changed, 50 insertions(+), 37 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index 58d876b184b..836597f95da 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -61,11 +61,6 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file, const char *object_path); void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader); -/* Determine whether the CacheFile should use a render engine procedural. If so, data is not read - * from the file and bouding boxes are used to represent the objects in the Scene. Render engines - * will receive the bounding box as a placeholder but can instead load the data directly if they - * support it. - */ bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, struct Scene *scene, const int dag_eval_mode); diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 4a60564b4a1..87b1584d422 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -368,7 +368,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file #endif if (DEG_is_active(depsgraph)) { - /* Flush object paths back to original datablock for UI. */ + /* Flush object paths back to original data-block for UI. */ CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id); BLI_freelistN(&cache_file_orig->object_paths); BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths); @@ -411,6 +411,12 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c return cache_file->is_sequence ? frame : frame / fps - time_offset; } +/** + * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read + * from the file and bounding boxes are used to represent the objects in the Scene. + * Render engines will receive the bounding box as a placeholder but can instead + * load the data directly if they support it. + */ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, Scene *scene, const int dag_eval_mode) diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index f4dc553e982..879a7b08eba 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -246,7 +246,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRW_shgroup_uniform_float_copy(grp, "studioLightIntensity", shading->studiolight_intensity); BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE); DRW_shgroup_uniform_texture_ex(grp, "studioLight", sl->equirect_radiance_gputexture, state); - /* Do not fadeout when doing probe rendering, only when drawing the background */ + /* Do not fade-out when doing probe rendering, only when drawing the background. */ DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); } else { diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 8640ffa67cf..a8bd3b11bb1 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -890,9 +890,9 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent } case MOUSEMOVE: /* calculate new position */ { - /* only handle mousemove if not doing numinput */ + /* Only handle mouse-move if not doing numeric-input. */ if (has_numinput == false) { - /* update shift based on position of mouse */ + /* Update shift based on position of mouse. */ gpencil_mouse_update_shift(tgpi, op, event); /* update screen */ diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 894fb83d70e..5ecb6d9a212 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1944,9 +1944,9 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e if (ELEM(tgpi->flag, IN_CURVE_EDIT)) { break; } - /* only handle mousemove if not doing numinput */ + /* Only handle mouse-move if not doing numeric-input. */ if (has_numinput == false) { - /* update position of mouse */ + /* Update position of mouse. */ copy_v2_v2(tgpi->end, tgpi->mval); copy_v2_v2(tgpi->start, tgpi->origin); if (tgpi->flag == IDLE) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index b8f324cba83..76f6640c714 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6025,7 +6025,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co * the slot menu fails to switch a second time. * * The active state of the button could be maintained some other way - * and remove this mousemove event. + * and remove this mouse-move event. */ WM_event_add_mousemove(data->window); @@ -8364,7 +8364,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s } } - /* wait for mousemove to enable drag */ + /* Wait for mouse-move to enable drag. */ if (state == BUTTON_STATE_WAIT_DRAG) { but->flag &= ~UI_SELECT; } @@ -8631,9 +8631,9 @@ static void button_activate_exit( ui_but_update(but); } - /* adds empty mousemove in queue for re-init handler, in case mouse is + /* Adds empty mouse-move in queue for re-initialize handler, in case mouse is * still over a button. We cannot just check for this ourselves because - * at this point the mouse may be over a button in another region */ + * at this point the mouse may be over a button in another region. */ if (mousemove) { WM_event_add_mousemove(CTX_wm_window(C)); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index b8bbf2d3e70..956658bd2b7 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -8627,7 +8627,7 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent * RNA_enum_set(op->ptr, "mode", mode); } - /* Only handle mousemove event in case we are in mouse mode. */ + /* Only handle mouse-move event in case we are in mouse mode. */ if (event->type == MOUSEMOVE || force_mousemove) { if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) { ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 85883a2d29a..8afc5c583e0 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -4667,7 +4667,7 @@ typedef struct BrushEdit { int lastmouse[2]; float zfac; - /* optional cached view settings to avoid setting on every mousemove */ + /** Optional cached view settings to avoid setting on every mouse-move. */ PEData data; } BrushEdit; diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 6db148eb4e1..8bc2281db73 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -64,7 +64,9 @@ #include -/***************************** Render Engines ********************************/ +/* -------------------------------------------------------------------- */ +/** \name Render Engines + * \{ */ /* Update 3D viewport render or draw engine on changes to the scene or view settings. */ void ED_render_view3d_update(Depsgraph *depsgraph, @@ -206,15 +208,15 @@ void ED_render_engine_changed(Main *bmain, const bool update_scene_data) } } - /* Update CacheFiles to ensure that procedurals are properly taken into account. */ + /* Update #CacheFiles to ensure that procedurals are properly taken into account. */ LISTBASE_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { - /* Only update cachefiles which are set to use a render procedural. We do not use - * BKE_cachefile_uses_render_procedural here as we need to update regardless of the current - * engine or its settings. */ + /* Only update cache-files which are set to use a render procedural. + * We do not use #BKE_cachefile_uses_render_procedural here as we need to update regardless of + * the current engine or its settings. */ if (cachefile->use_render_procedural) { DEG_id_tag_update(&cachefile->id, ID_RECALC_COPY_ON_WRITE); - /* Rebuild relations so that modifiers are reconnected to or disconnected from the cachefile. - */ + /* Rebuild relations so that modifiers are reconnected to or disconnected from the + * cache-file. */ DEG_relations_tag_update(bmain); } } @@ -227,10 +229,16 @@ void ED_render_view_layer_changed(Main *bmain, bScreen *screen) } } -/***************************** Updates *********************************** - * ED_render_id_flush_update gets called from DEG_id_tag_update, to do * - * editor level updates when the ID changes. when these ID blocks are in * - * the dependency graph, we can get rid of the manual dependency checks. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Updates + * + * #ED_render_id_flush_update gets called from #DEG_id_tag_update, + * to do editor level updates when the ID changes. + * When these ID blocks are in the dependency graph, + * we can get rid of the manual dependency checks. + * \{ */ static void material_changed(Main *UNUSED(bmain), Material *ma) { @@ -336,3 +344,5 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) break; } } + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 49299d73337..edc34d0d883 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -299,7 +299,9 @@ static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], cons ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co); } -/* use for mousemove events */ +/** + * Use for mouse-move events. + */ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, RulerInfo *ruler_info, RulerItem *ruler_item, diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index f56d60b7376..5627a910ab4 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -131,12 +131,12 @@ static void autokeyframe_pose( ListBase dsources = {NULL, NULL}; - /* add datasource override for the camera object */ + /* Add data-source override for the camera object. */ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); /* only insert into active keyingset? */ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) { - /* run the active Keying Set on the current datasource */ + /* Run the active Keying Set on the current data-source. */ ANIM_apply_keyingset( C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time); } diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index ee6cb391fdc..bcbac009948 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -749,7 +749,7 @@ static void autokeyframe_object( /* Get flags used for inserting keyframes. */ flag = ANIM_get_keyframing_flags(scene, true); - /* add datasource override for the object */ + /* Add data-source override for the object. */ ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL); if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) { diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c index be7fc65a6c2..08335924ddf 100644 --- a/source/blender/editors/transform/transform_snap_animation.c +++ b/source/blender/editors/transform/transform_snap_animation.c @@ -35,14 +35,14 @@ #include "transform_snap.h" /* -------------------------------------------------------------------- */ -/** \name Snappint in Anim Editors +/** \name Snapping in Anim Editors * \{ */ /** * This function returns the snapping 'mode' for Animation Editors only. * We cannot use the standard snapping due to NLA-strip scaling complexities. * - * TODO: these modifier checks should be key-mappable. + * TODO: these modifier checks should be accessible from the key-map. */ short getAnimEdit_SnapMode(TransInfo *t) { diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp index 355aa5c22f0..bd6f496c8ec 100644 --- a/source/blender/io/collada/collada_internal.cpp +++ b/source/blender/io/collada/collada_internal.cpp @@ -162,7 +162,7 @@ void UnitConverter::calculate_scale(Scene &sce) * Translation map. * Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be * included. Look at the IDREF XSD declaration for more. - * Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars, + * Follows strictly the COLLADA XSD declaration which explicitly allows non-English chars, * like special chars (e.g. micro sign), umlauts and so on. * The COLLADA spec also allows additional chars for member access ('.'), these * must obviously be removed too, otherwise they would be heavily misinterpreted. diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 5cc361fc1bd..b9a3dd0c3fb 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -3471,8 +3471,8 @@ void wm_event_do_handlers(bContext *C) } CTX_wm_area_set(C, NULL); - /* NOTE: do not escape on WM_HANDLER_BREAK, - * mousemove needs handled for previous area. */ + /* NOTE: do not escape on #WM_HANDLER_BREAK, + * mouse-move needs handled for previous area. */ } } -- cgit v1.2.3 From 47e68537f83075dd78ed66aac3216643389b0e3a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Aug 2021 17:41:40 +1000 Subject: Cleanup: organize blf_font.c functions using doxy-sections Functions in this file were scattered and not well organized. --- source/blender/blenfont/intern/blf_font.c | 743 ++++++++++++++++-------------- 1 file changed, 403 insertions(+), 340 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 436c4712e25..47fa3544474 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -71,6 +71,38 @@ static FT_Library ft_lib; static SpinLock ft_lib_mutex; static SpinLock blf_glyph_cache_mutex; +/* -------------------------------------------------------------------- */ +/** \name FreeType Utilities (Internal) + * \{ */ + +/** + * Convert a FreeType 26.6 value representing an unscaled design size to pixels. + * This is an exact copy of the scaling done inside FT_Get_Kerning when called + * with #FT_KERNING_DEFAULT, including arbitrary resizing for small fonts. + */ +static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) +{ + /* Scale value by font size using integer-optimized multiplication. */ + FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale); + + /* FreeType states that this '25' has been determined heuristically. */ + if (font->face->size->metrics.x_ppem < 25) { + scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25); + } + + /* Copies of internal FreeType macros needed here. */ +#define FT_PIX_FLOOR(x) ((x) & ~63) +#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32) + + /* Round to even 64ths, then divide by 64. */ + return (int)FT_PIX_ROUND(scaled) >> 6; + +#undef FT_PIX_FLOOR +#undef FT_PIX_ROUND +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Glyph Batching * \{ */ @@ -257,56 +289,8 @@ static void blf_batch_draw_end(void) /** \} */ /* -------------------------------------------------------------------- */ - -int blf_font_init(void) -{ - memset(&g_batch, 0, sizeof(g_batch)); - BLI_spin_init(&ft_lib_mutex); - BLI_spin_init(&blf_glyph_cache_mutex); - return FT_Init_FreeType(&ft_lib); -} - -void blf_font_exit(void) -{ - FT_Done_FreeType(ft_lib); - BLI_spin_end(&ft_lib_mutex); - BLI_spin_end(&blf_glyph_cache_mutex); - blf_batch_draw_exit(); -} - -void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) -{ - GlyphCacheBLF *gc; - FT_Error err; - - blf_glyph_cache_acquire(font); - - gc = blf_glyph_cache_find(font, size, dpi); - if (gc) { - /* Optimization: do not call FT_Set_Char_Size if size did not change. */ - if (font->size == size && font->dpi == dpi) { - blf_glyph_cache_release(font); - return; - } - } - - err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); - if (err) { - /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); - - blf_glyph_cache_release(font); - return; - } - - font->size = size; - font->dpi = dpi; - - if (!gc) { - blf_glyph_cache_new(font); - } - blf_glyph_cache_release(font); -} +/** \name Glyph Stepping Utilities (Internal) + * \{ */ /* Fast path for runs of ASCII characters. Given that common UTF-8 * input will consist of an overwhelming majority of ASCII @@ -337,31 +321,6 @@ BLI_INLINE GlyphBLF *blf_utf8_next_fast( return g; } -/* Convert a FreeType 26.6 value representing an unscaled design size to pixels. - * This is an exact copy of the scaling done inside FT_Get_Kerning when called - * with FT_KERNING_DEFAULT, including arbitrary resizing for small fonts. - */ -static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) -{ - /* Scale value by font size using integer-optimized multiplication. */ - FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale); - - /* FreeType states that this '25' has been determined heuristically. */ - if (font->face->size->metrics.x_ppem < 25) { - scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25); - } - - /* Copies of internal FreeType macros needed here. */ -#define FT_PIX_FLOOR(x) ((x) & ~63) -#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32) - - /* Round to even 64ths, then divide by 64. */ - return (int)FT_PIX_ROUND(scaled) >> 6; - -#undef FT_PIX_FLOOR -#undef FT_PIX_ROUND -} - BLI_INLINE void blf_kerning_step_fast(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g, @@ -395,6 +354,12 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Text Drawing: GPU + * \{ */ + static void blf_font_draw_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, @@ -535,6 +500,12 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) return columns; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Text Drawgin: Buffer + * \{ */ + /* Sanity checks are done by BLF_draw_buffer() */ static void blf_font_draw_buffer_ex(FontBLF *font, GlyphCacheBLF *gc, @@ -680,6 +651,16 @@ void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct Res blf_glyph_cache_release(font); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Text Evaluation: Width to Sting Length + * + * Use to implement exported functions: + * - #BLF_width_to_strlen + * - #BLF_width_to_rstrlen + * \{ */ + static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, const uint c_prev, const uint c, @@ -773,6 +754,12 @@ size_t blf_font_width_to_rstrlen( return i; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Text Evaluation: Glyph Bound Box with Callback + * \{ */ + static void blf_font_boundbox_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, @@ -847,73 +834,230 @@ void blf_font_boundbox( blf_glyph_cache_release(font); } -/* -------------------------------------------------------------------- */ -/** \name Word-Wrap Support - * \{ */ +void blf_font_width_and_height(FontBLF *font, + const char *str, + size_t len, + float *r_width, + float *r_height, + struct ResultBLF *r_info) +{ + float xa, ya; + rctf box; -/** - * Generic function to add word-wrap support for other existing functions. - * - * Wraps on spaces and respects newlines. - * Intentionally ignores non-unix newlines, tabs and more advanced text formatting. - * - * \note If we want rich text - we better have a higher level API to handle that - * (color, bold, switching fonts... etc). - */ -static void blf_font_wrap_apply(FontBLF *font, - const char *str, - size_t len, - struct ResultBLF *r_info, - void (*callback)(FontBLF *font, - GlyphCacheBLF *gc, - const char *str, - size_t len, - int pen_y, - void *userdata), - void *userdata) + if (font->flags & BLF_ASPECT) { + xa = font->aspect[0]; + ya = font->aspect[1]; + } + else { + xa = 1.0f; + ya = 1.0f; + } + + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } + *r_width = (BLI_rctf_size_x(&box) * xa); + *r_height = (BLI_rctf_size_y(&box) * ya); +} + +float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) { - unsigned int c, c_prev = BLI_UTF8_ERR; - GlyphBLF *g, *g_prev = NULL; - int pen_x = 0, pen_y = 0; - size_t i = 0; - int lines = 0; - int pen_x_next = 0; + float xa; + rctf box; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + if (font->flags & BLF_ASPECT) { + xa = font->aspect[0]; + } + else { + xa = 1.0f; + } - struct WordWrapVars { - int wrap_width; - size_t start, last[2]; - } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}}; + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } + return BLI_rctf_size_x(&box) * xa; +} - // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str); - while ((i < len) && str[i]) { +float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + float ya; + rctf box; - /* wrap vars */ - size_t i_curr = i; - bool do_draw = false; + if (font->flags & BLF_ASPECT) { + ya = font->aspect[1]; + } + else { + ya = 1.0f; + } - g = blf_utf8_next_fast(font, gc, str, &i, &c); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } + return BLI_rctf_size_y(&box) * ya; +} - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } - if (UNLIKELY(g == NULL)) { - continue; - } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); +float blf_font_fixed_width(FontBLF *font) +{ + const unsigned int c = ' '; - /** - * Implementation Detail (utf8). - * - * Take care with single byte offsets here, - * since this is utf8 we can't be sure a single byte is a single character. - * - * This is _only_ done when we know for sure the character is ascii (newline or a space). - */ - pen_x_next = pen_x + g->advance_i; - if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) { - do_draw = true; + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphBLF *g = blf_glyph_search(gc, c); + if (!g) { + g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c); + + /* if we don't find the glyph. */ + if (!g) { + blf_glyph_cache_release(font); + return 0.0f; + } + } + + blf_glyph_cache_release(font); + return g->advance; +} + +static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, + GlyphCacheBLF *gc, + const char *str, + size_t len, + BLF_GlyphBoundsFn user_fn, + void *user_data, + struct ResultBLF *r_info, + int pen_y) +{ + unsigned int c, c_prev = BLI_UTF8_ERR; + GlyphBLF *g, *g_prev = NULL; + int pen_x = 0; + size_t i = 0, i_curr; + rcti gbox; + + if (len == 0) { + /* early output. */ + return; + } + + while ((i < len) && str[i]) { + i_curr = i; + g = blf_utf8_next_fast(font, gc, str, &i, &c); + + if (UNLIKELY(c == BLI_UTF8_ERR)) { + break; + } + if (UNLIKELY(g == NULL)) { + continue; + } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + + gbox.xmin = pen_x; + gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); + gbox.ymin = pen_y; + gbox.ymax = gbox.ymin - g->dims[1]; + + pen_x += g->advance_i; + + if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) { + break; + } + + g_prev = g; + c_prev = c; + } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_boundbox_foreach_glyph(FontBLF *font, + const char *str, + size_t len, + BLF_GlyphBoundsFn user_fn, + void *user_data, + struct ResultBLF *r_info) +{ + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + blf_font_boundbox_foreach_glyph_ex(font, gc, str, len, user_fn, user_data, r_info, 0); + blf_glyph_cache_release(font); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Text Evaluation: Word-Wrap with Callback + * \{ */ + +/** + * Generic function to add word-wrap support for other existing functions. + * + * Wraps on spaces and respects newlines. + * Intentionally ignores non-unix newlines, tabs and more advanced text formatting. + * + * \note If we want rich text - we better have a higher level API to handle that + * (color, bold, switching fonts... etc). + */ +static void blf_font_wrap_apply(FontBLF *font, + const char *str, + size_t len, + struct ResultBLF *r_info, + void (*callback)(FontBLF *font, + GlyphCacheBLF *gc, + const char *str, + size_t len, + int pen_y, + void *userdata), + void *userdata) +{ + unsigned int c, c_prev = BLI_UTF8_ERR; + GlyphBLF *g, *g_prev = NULL; + int pen_x = 0, pen_y = 0; + size_t i = 0; + int lines = 0; + int pen_x_next = 0; + + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + + struct WordWrapVars { + int wrap_width; + size_t start, last[2]; + } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}}; + + // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str); + while ((i < len) && str[i]) { + + /* wrap vars */ + size_t i_curr = i; + bool do_draw = false; + + g = blf_utf8_next_fast(font, gc, str, &i, &c); + + if (UNLIKELY(c == BLI_UTF8_ERR)) { + break; + } + if (UNLIKELY(g == NULL)) { + continue; + } + blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + + /** + * Implementation Detail (utf8). + * + * Take care with single byte offsets here, + * since this is utf8 we can't be sure a single byte is a single character. + * + * This is _only_ done when we know for sure the character is ascii (newline or a space). + */ + pen_x_next = pen_x + g->advance_i; + if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) { + do_draw = true; } else if (UNLIKELY(((i < len) && str[i]) == 0)) { /* need check here for trailing newline, else we draw it */ @@ -1018,216 +1162,120 @@ void blf_font_draw_buffer__wrap(FontBLF *font, /** \} */ -void blf_font_width_and_height(FontBLF *font, - const char *str, - size_t len, - float *r_width, - float *r_height, - struct ResultBLF *r_info) +/* -------------------------------------------------------------------- */ +/** \name Text Evaluation: Count Missing Characters + * \{ */ + +int blf_font_count_missing_chars(FontBLF *font, + const char *str, + const size_t len, + int *r_tot_chars) { - float xa, ya; - rctf box; + int missing = 0; + size_t i = 0; - if (font->flags & BLF_ASPECT) { - xa = font->aspect[0]; - ya = font->aspect[1]; - } - else { - xa = 1.0f; - ya = 1.0f; - } + *r_tot_chars = 0; + while (i < len) { + unsigned int c; - if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); - } - else { - blf_font_boundbox(font, str, len, &box, r_info); + if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) { + i++; + } + else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) { + if (FT_Get_Char_Index((font)->face, c) == 0) { + missing++; + } + } + (*r_tot_chars)++; } - *r_width = (BLI_rctf_size_x(&box) * xa); - *r_height = (BLI_rctf_size_y(&box) * ya); + return missing; } -float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) -{ - float xa; - rctf box; - - if (font->flags & BLF_ASPECT) { - xa = font->aspect[0]; - } - else { - xa = 1.0f; - } +/** \} */ - if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); - } - else { - blf_font_boundbox(font, str, len, &box, r_info); - } - return BLI_rctf_size_x(&box) * xa; -} +/* -------------------------------------------------------------------- */ +/** \name Font Query: Attributes + * \{ */ -float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +int blf_font_height_max(FontBLF *font) { - float ya; - rctf box; + int height_max; - if (font->flags & BLF_ASPECT) { - ya = font->aspect[1]; - } - else { - ya = 1.0f; - } + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + height_max = gc->glyph_height_max; - if (font->flags & BLF_WORD_WRAP) { - blf_font_boundbox__wrap(font, str, len, &box, r_info); - } - else { - blf_font_boundbox(font, str, len, &box, r_info); - } - return BLI_rctf_size_y(&box) * ya; + blf_glyph_cache_release(font); + return height_max; } -float blf_font_fixed_width(FontBLF *font) +int blf_font_width_max(FontBLF *font) { - const unsigned int c = ' '; + int width_max; GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF *g = blf_glyph_search(gc, c); - if (!g) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c); - - /* if we don't find the glyph. */ - if (!g) { - blf_glyph_cache_release(font); - return 0.0f; - } - } + width_max = gc->glyph_width_max; blf_glyph_cache_release(font); - return g->advance; + return width_max; } -/* -------------------------------------------------------------------- */ -/** \name Glyph Bound Box with Callback - * \{ */ - -static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, - GlyphCacheBLF *gc, - const char *str, - size_t len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info, - int pen_y) +float blf_font_descender(FontBLF *font) { - unsigned int c, c_prev = BLI_UTF8_ERR; - GlyphBLF *g, *g_prev = NULL; - int pen_x = 0; - size_t i = 0, i_curr; - rcti gbox; - - if (len == 0) { - /* early output. */ - return; - } - - while ((i < len) && str[i]) { - i_curr = i; - g = blf_utf8_next_fast(font, gc, str, &i, &c); - - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } - if (UNLIKELY(g == NULL)) { - continue; - } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + float descender; - gbox.xmin = pen_x; - gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); - gbox.ymin = pen_y; - gbox.ymax = gbox.ymin - g->dims[1]; + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + descender = gc->descender; - pen_x += g->advance_i; + blf_glyph_cache_release(font); + return descender; +} - if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) { - break; - } +float blf_font_ascender(FontBLF *font) +{ + float ascender; - g_prev = g; - c_prev = c; - } + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + ascender = gc->ascender; - if (r_info) { - r_info->lines = 1; - r_info->width = pen_x; - } + blf_glyph_cache_release(font); + return ascender; } -void blf_font_boundbox_foreach_glyph(FontBLF *font, - const char *str, - size_t len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info) + +char *blf_display_name(FontBLF *font) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_boundbox_foreach_glyph_ex(font, gc, str, len, user_fn, user_data, r_info, 0); - blf_glyph_cache_release(font); + if (!font->face->family_name) { + return NULL; + } + return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name); } /** \} */ -int blf_font_count_missing_chars(FontBLF *font, - const char *str, - const size_t len, - int *r_tot_chars) -{ - int missing = 0; - size_t i = 0; - - *r_tot_chars = 0; - while (i < len) { - unsigned int c; +/* -------------------------------------------------------------------- */ +/** \name Font Subsystem Init/Exit + * \{ */ - if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) { - i++; - } - else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) { - if (FT_Get_Char_Index((font)->face, c) == 0) { - missing++; - } - } - (*r_tot_chars)++; - } - return missing; +int blf_font_init(void) +{ + memset(&g_batch, 0, sizeof(g_batch)); + BLI_spin_init(&ft_lib_mutex); + BLI_spin_init(&blf_glyph_cache_mutex); + return FT_Init_FreeType(&ft_lib); } -void blf_font_free(FontBLF *font) +void blf_font_exit(void) { - BLI_spin_lock(&blf_glyph_cache_mutex); - GlyphCacheBLF *gc; - - while ((gc = BLI_pophead(&font->cache))) { - blf_glyph_cache_free(gc); - } - - if (font->kerning_cache) { - MEM_freeN(font->kerning_cache); - } + FT_Done_FreeType(ft_lib); + BLI_spin_end(&ft_lib_mutex); + BLI_spin_end(&blf_glyph_cache_mutex); + blf_batch_draw_exit(); +} - FT_Done_Face(font->face); - if (font->filename) { - MEM_freeN(font->filename); - } - if (font->name) { - MEM_freeN(font->name); - } - MEM_freeN(font); +/** \} */ - BLI_spin_unlock(&blf_glyph_cache_mutex); -} +/* -------------------------------------------------------------------- */ +/** \name Font New/Free + * \{ */ static void blf_font_fill(FontBLF *font) { @@ -1366,54 +1414,69 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m return font; } -int blf_font_height_max(FontBLF *font) +void blf_font_free(FontBLF *font) { - int height_max; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - height_max = gc->glyph_height_max; + BLI_spin_lock(&blf_glyph_cache_mutex); + GlyphCacheBLF *gc; - blf_glyph_cache_release(font); - return height_max; -} + while ((gc = BLI_pophead(&font->cache))) { + blf_glyph_cache_free(gc); + } -int blf_font_width_max(FontBLF *font) -{ - int width_max; + if (font->kerning_cache) { + MEM_freeN(font->kerning_cache); + } - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - width_max = gc->glyph_width_max; + FT_Done_Face(font->face); + if (font->filename) { + MEM_freeN(font->filename); + } + if (font->name) { + MEM_freeN(font->name); + } + MEM_freeN(font); - blf_glyph_cache_release(font); - return width_max; + BLI_spin_unlock(&blf_glyph_cache_mutex); } -float blf_font_descender(FontBLF *font) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Font Configure + * \{ */ + +void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) { - float descender; + GlyphCacheBLF *gc; + FT_Error err; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - descender = gc->descender; + blf_glyph_cache_acquire(font); - blf_glyph_cache_release(font); - return descender; -} + gc = blf_glyph_cache_find(font, size, dpi); + if (gc) { + /* Optimization: do not call FT_Set_Char_Size if size did not change. */ + if (font->size == size && font->dpi == dpi) { + blf_glyph_cache_release(font); + return; + } + } -float blf_font_ascender(FontBLF *font) -{ - float ascender; + err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); + if (err) { + /* FIXME: here we can go through the fixed size and choice a close one */ + printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - ascender = gc->ascender; + blf_glyph_cache_release(font); + return; + } - blf_glyph_cache_release(font); - return ascender; -} + font->size = size; + font->dpi = dpi; -char *blf_display_name(FontBLF *font) -{ - if (!font->face->family_name) { - return NULL; + if (!gc) { + blf_glyph_cache_new(font); } - return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name); + blf_glyph_cache_release(font); } + +/** \} */ -- cgit v1.2.3 From 0b7947e85528bbf5c4e1f41354a41dc113937088 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Aug 2021 17:44:25 +1000 Subject: Cleanup: minor changes to blf_font.c - Use early return when kerning isn't used. - Remove early return that prevented matching acquire/release calls. --- source/blender/blenfont/intern/blf_font.c | 78 ++++++++++++++----------------- 1 file changed, 36 insertions(+), 42 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 47fa3544474..75a2e893119 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -328,29 +328,31 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, const uint c, int *pen_x_p) { - if (FT_HAS_KERNING(font->face) && g_prev != NULL) { - FT_Vector delta = {KERNING_ENTRY_UNSET}; + if (!FT_HAS_KERNING(font->face) || g_prev == NULL) { + return; + } - /* Get unscaled kerning value from our cache if ASCII. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - delta.x = font->kerning_cache->ascii_table[c][c_prev]; - } + FT_Vector delta = {KERNING_ENTRY_UNSET}; - /* If not ASCII or not found in cache, ask FreeType for kerning. */ - if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) { - /* Note that this function sets delta values to zero on any error. */ - FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta); - } + /* Get unscaled kerning value from our cache if ASCII. */ + if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { + delta.x = font->kerning_cache->ascii_table[c][c_prev]; + } - /* If ASCII we save this value to our cache for quicker access next time. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x; - } + /* If not ASCII or not found in cache, ask FreeType for kerning. */ + if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) { + /* Note that this function sets delta values to zero on any error. */ + FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta); + } - if (delta.x != 0) { - /* Convert unscaled design units to pixels and move pen. */ - *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x); - } + /* If ASCII we save this value to our cache for quicker access next time. */ + if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { + font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x; + } + + if (delta.x != 0) { + /* Convert unscaled design units to pixels and move pen. */ + *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x); } } @@ -1447,35 +1449,27 @@ void blf_font_free(FontBLF *font) void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) { - GlyphCacheBLF *gc; - FT_Error err; - blf_glyph_cache_acquire(font); - gc = blf_glyph_cache_find(font, size, dpi); - if (gc) { + GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi); + if (gc && (font->size == size && font->dpi == dpi)) { /* Optimization: do not call FT_Set_Char_Size if size did not change. */ - if (font->size == size && font->dpi == dpi) { - blf_glyph_cache_release(font); - return; - } } - - err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); - if (err) { - /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); - - blf_glyph_cache_release(font); - return; + else { + const FT_Error err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); + if (err) { + /* FIXME: here we can go through the fixed size and choice a close one */ + printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); + } + else { + font->size = size; + font->dpi = dpi; + if (gc == NULL) { + blf_glyph_cache_new(font); + } + } } - font->size = size; - font->dpi = dpi; - - if (!gc) { - blf_glyph_cache_new(font); - } blf_glyph_cache_release(font); } -- cgit v1.2.3