diff options
author | Fabian Schempp <fabianschempp@googlemail.com> | 2022-04-11 08:14:28 +0300 |
---|---|---|
committer | Fabian Schempp <fabianschempp@googlemail.com> | 2022-04-11 08:14:28 +0300 |
commit | f06d361da1249c93568153bae88bcdf43b4774a1 (patch) | |
tree | 5acd7443d2c13d3f89b40e81f7d93df5e2a56008 | |
parent | ab6939ff78f131e5270e17b9ee73075b512a1a3f (diff) | |
parent | 5e47056e8d97e414c9dabacea71fac2bdc7d2818 (diff) |
Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-remesh-voxel
# Conflicts:
# intern/cycles/app/opengl/display_driver.cpp
# intern/cycles/app/opengl/display_driver.h
# intern/cycles/app/opengl/shader.cpp
# intern/cycles/app/opengl/shader.h
# intern/cycles/app/opengl/window.cpp
# intern/cycles/app/opengl/window.h
# intern/cycles/blender/addon/ui.py
# intern/cycles/util/view.cpp
# intern/cycles/util/view.h
# release/scripts/startup/bl_ui/properties_data_armature.py
# release/scripts/startup/bl_ui/properties_view_layer.py
# source/blender/blenkernel/BKE_armature.h
# source/blender/blenkernel/BKE_blender_version.h
# source/blender/blenkernel/BKE_curves.hh
# source/blender/blenkernel/BKE_gpencil_update_cache.h
# source/blender/blenkernel/BKE_node.h
# source/blender/blenkernel/CMakeLists.txt
# source/blender/blenkernel/intern/curve_eval.cc
# source/blender/blenkernel/intern/curves_geometry.cc
# source/blender/blenkernel/intern/geometry_component_curves.cc
# source/blender/blenkernel/intern/lib_override.c
# source/blender/blenkernel/intern/lib_override_proxy_conversion.c
# source/blender/blenkernel/intern/scene.cc
# source/blender/blenkernel/intern/type_conversions.cc
# source/blender/blenloader/intern/versioning_300.c
# source/blender/draw/engines/eevee/eevee_data.c
# source/blender/draw/engines/image/image_drawing_mode.hh
# source/blender/draw/engines/image/image_space.hh
# source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
# source/blender/draw/intern/draw_cache_impl_subdivision.cc
# source/blender/editors/gpencil/gpencil_fill.c
# source/blender/editors/include/ED_paint.h
# source/blender/editors/object/object_bake.c
# source/blender/editors/render/render_intern.hh
# source/blender/editors/render/render_ops.cc
# source/blender/editors/render/render_shading.cc
# source/blender/editors/screen/area.c
# source/blender/editors/sculpt_paint/paint_canvas.cc
# source/blender/editors/sculpt_paint/sculpt_intern.h
# source/blender/editors/sculpt_paint/sculpt_paint_color.c
# source/blender/editors/space_node/node_intern.hh
# source/blender/editors/space_outliner/outliner_tools.cc
# source/blender/editors/transform/transform_convert_sequencer.c
# source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
# source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
# source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
# source/blender/makesdna/DNA_ID.h
# source/blender/makesdna/DNA_curves_types.h
# source/blender/makesrna/intern/rna_internal.h
# source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
# source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
95 files changed, 1574 insertions, 966 deletions
diff --git a/intern/cycles/app/opengl/display_driver.cpp b/intern/cycles/app/opengl/display_driver.cpp index b86a2b80713..8b99f3b6feb 100644 --- a/intern/cycles/app/opengl/display_driver.cpp +++ b/intern/cycles/app/opengl/display_driver.cpp @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ #include "app/opengl/display_driver.h" #include "app/opengl/shader.h" diff --git a/intern/cycles/app/opengl/display_driver.h b/intern/cycles/app/opengl/display_driver.h index 7645d7905b4..92578412d68 100644 --- a/intern/cycles/app/opengl/display_driver.h +++ b/intern/cycles/app/opengl/display_driver.h @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ #pragma once diff --git a/intern/cycles/app/opengl/shader.cpp b/intern/cycles/app/opengl/shader.cpp index 48ccafa0d95..9db9ea7fce9 100644 --- a/intern/cycles/app/opengl/shader.cpp +++ b/intern/cycles/app/opengl/shader.cpp @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ #include "app/opengl/shader.h" diff --git a/intern/cycles/app/opengl/shader.h b/intern/cycles/app/opengl/shader.h index 682463891d5..6ca121ca6ff 100644 --- a/intern/cycles/app/opengl/shader.h +++ b/intern/cycles/app/opengl/shader.h @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 OpenGL Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 OpenGL Foundation */ #pragma once diff --git a/intern/cycles/app/opengl/window.cpp b/intern/cycles/app/opengl/window.cpp index 4da0ebdece5..7351ae3eecd 100644 --- a/intern/cycles/app/opengl/window.cpp +++ b/intern/cycles/app/opengl/window.cpp @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ #include <stdio.h> #include <stdlib.h> diff --git a/intern/cycles/app/opengl/window.h b/intern/cycles/app/opengl/window.h index 4f9e418e5c2..531b5cab3fc 100644 --- a/intern/cycles/app/opengl/window.h +++ b/intern/cycles/app/opengl/window.h @@ -1,18 +1,5 @@ -/* - * Copyright 2011-2022 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ #pragma once diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index b7713dc7110..61f47c0765b 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -226,7 +226,11 @@ def list_render_passes(scene, srl): if aov.type == 'VALUE': yield (aov.name, "X", 'VALUE') else: - yield (aov.name, "RGB", 'COLOR') + yield (aov.name, "RGBA", 'COLOR') + + # Light groups. + for lightgroup in srl.lightgroups: + yield ("Combined_%s" % lightgroup.name, "RGB", 'COLOR') # Light groups. for lightgroup in srl.lightgroups: diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 2c6788b867b..739a555f037 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1916,13 +1916,20 @@ class CYCLES_RENDER_PT_bake_output_margin(CyclesButtonsPanel, Panel): cbk = scene.render.bake rd = scene.render - if rd.use_bake_multires: - layout.prop(rd, "bake_margin_type", text="Type") - layout.prop(rd, "bake_margin", text="Size") + if (cscene.bake_type == 'NORMAL' and cbk.normal_space == 'TANGENT') or cscene.bake_type == 'UV': + if rd.use_bake_multires: + layout.prop(rd, "bake_margin", text="Size") + else: + if cbk.target == 'IMAGE_TEXTURES': + layout.prop(cbk, "margin", text="Size") else: - if cbk.target == 'IMAGE_TEXTURES': - layout.prop(cbk, "margin_type", text="Type") - layout.prop(cbk, "margin", text="Size") + if rd.use_bake_multires: + layout.prop(rd, "bake_margin_type", text="Type") + layout.prop(rd, "bake_margin", text="Size") + else: + if cbk.target == 'IMAGE_TEXTURES': + layout.prop(cbk, "margin_type", text="Type") + layout.prop(cbk, "margin", text="Size") diff --git a/intern/cycles/kernel/svm/aov.h b/intern/cycles/kernel/svm/aov.h index 334fb79cb75..9b818f0e6f8 100644 --- a/intern/cycles/kernel/svm/aov.h +++ b/intern/cycles/kernel/svm/aov.h @@ -32,7 +32,7 @@ ccl_device void svm_node_aov_color(KernelGlobals kg, kernel_data.film.pass_stride; ccl_global float *buffer = render_buffer + render_buffer_offset + (kernel_data.film.pass_aov_color + node.z); - kernel_write_pass_float3(buffer, make_float3(val.x, val.y, val.z)); + kernel_write_pass_float4(buffer, make_float4(val.x, val.y, val.z, 1.0f)); } } diff --git a/intern/cycles/scene/pass.cpp b/intern/cycles/scene/pass.cpp index 5f5b19e710d..c2f12355ac7 100644 --- a/intern/cycles/scene/pass.cpp +++ b/intern/cycles/scene/pass.cpp @@ -321,7 +321,7 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo, const bo break; case PASS_AOV_COLOR: - pass_info.num_components = 3; + pass_info.num_components = 4; break; case PASS_AOV_VALUE: pass_info.num_components = 1; diff --git a/intern/cycles/util/view.cpp b/intern/cycles/util/view.cpp deleted file mode 100644 index 475f8dbcee8..00000000000 --- a/intern/cycles/util/view.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#include <stdio.h> -#include <stdlib.h> - -#include "util/opengl.h" -#include "util/string.h" -#include "util/time.h" -#include "util/version.h" -#include "util/view.h" - -#ifdef __APPLE__ -# include <GLUT/glut.h> -#else -# include <GL/glut.h> -#endif - -CCL_NAMESPACE_BEGIN - -/* structs */ - -struct View { - ViewInitFunc initf; - ViewExitFunc exitf; - ViewResizeFunc resize; - ViewDisplayFunc display; - ViewKeyboardFunc keyboard; - ViewMotionFunc motion; - - bool first_display; - bool redraw; - - int mouseX, mouseY; - int mouseBut0, mouseBut2; - - int width, height; -} V; - -/* public */ - -static void view_display_text(int x, int y, const char *text) -{ - const char *c; - - glRasterPos3f(x, y, 0); - - for (c = text; *c != '\0'; c++) - glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c); -} - -void view_display_info(const char *info) -{ - const int height = 20; - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(0.1f, 0.1f, 0.1f, 0.8f); - glRectf(0.0f, V.height - height, V.width, V.height); - glDisable(GL_BLEND); - - glColor3f(0.5f, 0.5f, 0.5f); - - view_display_text(10, 7 + V.height - height, info); - - glColor3f(1.0f, 1.0f, 1.0f); -} - -void view_display_help() -{ - const int w = (int)((float)V.width / 1.15f); - const int h = (int)((float)V.height / 1.15f); - - const int x1 = (V.width - w) / 2; - const int x2 = x1 + w; - - const int y1 = (V.height - h) / 2; - const int y2 = y1 + h; - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(0.5f, 0.5f, 0.5f, 0.8f); - glRectf(x1, y1, x2, y2); - glDisable(GL_BLEND); - - glColor3f(0.8f, 0.8f, 0.8f); - - string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING; - - view_display_text(x1 + 20, y2 - 20, info.c_str()); - view_display_text(x1 + 20, y2 - 40, "(C) 2011-2022 Blender Foundation"); - view_display_text(x1 + 20, y2 - 80, "Controls:"); - view_display_text(x1 + 20, y2 - 100, "h: Info/Help"); - view_display_text(x1 + 20, y2 - 120, "r: Reset"); - view_display_text(x1 + 20, y2 - 140, "p: Pause"); - view_display_text(x1 + 20, y2 - 160, "esc: Cancel"); - view_display_text(x1 + 20, y2 - 180, "q: Quit program"); - - view_display_text(x1 + 20, y2 - 210, "i: Interactive mode"); - view_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera"); - view_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera"); - view_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera"); - view_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces"); - - glColor3f(1.0f, 1.0f, 1.0f); -} - -static void view_display() -{ - if (V.first_display) { - if (V.initf) - V.initf(); - if (V.exitf) - atexit(V.exitf); - - V.first_display = false; - } - - glClearColor(0.05f, 0.05f, 0.05f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, V.width, 0, V.height, -1, 1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glRasterPos3f(0, 0, 0); - - if (V.display) - V.display(); - - glutSwapBuffers(); -} - -static void view_reshape(int width, int height) -{ - if (width <= 0 || height <= 0) - return; - - V.width = width; - V.height = height; - - glViewport(0, 0, width, height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - if (V.resize) - V.resize(width, height); -} - -static void view_keyboard(unsigned char key, int x, int y) -{ - if (V.keyboard) - V.keyboard(key); - - if (key == 'm') - printf("mouse %d %d\n", x, y); - if (key == 'q') { - if (V.exitf) - V.exitf(); - exit(0); - } -} - -static void view_mouse(int button, int state, int x, int y) -{ - if (button == 0) { - if (state == GLUT_DOWN) { - V.mouseX = x; - V.mouseY = y; - V.mouseBut0 = 1; - } - else if (state == GLUT_UP) { - V.mouseBut0 = 0; - } - } - else if (button == 2) { - if (state == GLUT_DOWN) { - V.mouseX = x; - V.mouseY = y; - V.mouseBut2 = 1; - } - else if (state == GLUT_UP) { - V.mouseBut2 = 0; - } - } -} - -static void view_motion(int x, int y) -{ - const int but = V.mouseBut0 ? 0 : 2; - const int distX = x - V.mouseX; - const int distY = y - V.mouseY; - - if (V.motion) - V.motion(distX, distY, but); - - V.mouseX = x; - V.mouseY = y; -} - -static void view_idle() -{ - if (V.redraw) { - V.redraw = false; - glutPostRedisplay(); - } - - time_sleep(0.1); -} - -void view_main_loop(const char *title, - int width, - int height, - ViewInitFunc initf, - ViewExitFunc exitf, - ViewResizeFunc resize, - ViewDisplayFunc display, - ViewKeyboardFunc keyboard, - ViewMotionFunc motion) -{ - const char *name = "app"; - char *argv = (char *)name; - int argc = 1; - - memset(&V, 0, sizeof(V)); - V.width = width; - V.height = height; - V.first_display = true; - V.redraw = false; - V.initf = initf; - V.exitf = exitf; - V.resize = resize; - V.display = display; - V.keyboard = keyboard; - V.motion = motion; - - glutInit(&argc, &argv); - glutInitWindowSize(width, height); - glutInitWindowPosition(0, 0); - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); - glutCreateWindow(title); - - glewInit(); - - view_reshape(width, height); - - glutDisplayFunc(view_display); - glutIdleFunc(view_idle); - glutReshapeFunc(view_reshape); - glutKeyboardFunc(view_keyboard); - glutMouseFunc(view_mouse); - glutMotionFunc(view_motion); - - glutMainLoop(); -} - -void view_redraw() -{ - V.redraw = true; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/util/view.h b/intern/cycles/util/view.h deleted file mode 100644 index 51c242c21f7..00000000000 --- a/intern/cycles/util/view.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#ifndef __UTIL_VIEW_H__ -#define __UTIL_VIEW_H__ - -/* Functions to display a simple OpenGL window using GLUT, simplified to the - * bare minimum we need to reduce boilerplate code in tests apps. */ - -CCL_NAMESPACE_BEGIN - -typedef void (*ViewInitFunc)(); -typedef void (*ViewExitFunc)(); -typedef void (*ViewResizeFunc)(int width, int height); -typedef void (*ViewDisplayFunc)(); -typedef void (*ViewKeyboardFunc)(unsigned char key); -typedef void (*ViewMotionFunc)(int x, int y, int button); - -void view_main_loop(const char *title, - int width, - int height, - ViewInitFunc initf, - ViewExitFunc exitf, - ViewResizeFunc resize, - ViewDisplayFunc display, - ViewKeyboardFunc keyboard, - ViewMotionFunc motion); - -void view_display_info(const char *info); -void view_display_help(); -void view_redraw(); - -CCL_NAMESPACE_END - -#endif /*__UTIL_VIEW_H__*/ diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 620b85f16d03a6aadd7cae56969c9c29b06b992 +Subproject 716dc02ec30c0810513f7b4adc4ae865ae50c4e diff --git a/release/scripts/addons b/release/scripts/addons -Subproject c08568cc376d2e4298710c4172fb0c74f0611de +Subproject 787ea78f7fa6f0373d80ba1247768402df93f8a diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject 7936dde9ece881d531b1a2ee6c45ddb56d30038 +Subproject 61e45814503f51963c91c51aaf764612e7c5dc7 diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py index 63ee2d1144e..af6634a791a 100644 --- a/release/scripts/modules/rna_manual_reference.py +++ b/release/scripts/modules/rna_manual_reference.py @@ -47,7 +47,6 @@ url_manual_mapping = ( ("bpy.types.lineartgpencilmodifier.use_offset_towards_custom_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-offset-towards-custom-camera"), ("bpy.types.movietrackingsettings.refine_intrinsics_principal_point*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-principal-point"), ("bpy.types.cyclesobjectsettings.shadow_terminator_geometry_offset*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-shadow-terminator-geometry-offset"), - ("bpy.types.cyclesrenderlayersettings.denoising_optix_input_passes*", "render/layers/denoising.html#bpy-types-cyclesrenderlayersettings-denoising-optix-input-passes"), ("bpy.types.sequencertoolsettings.use_snap_current_frame_to_strips*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-use-snap-current-frame-to-strips"), ("bpy.types.fluiddomainsettings.sndparticle_potential_max_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-energy"), ("bpy.types.fluiddomainsettings.sndparticle_potential_min_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-energy"), @@ -111,6 +110,7 @@ url_manual_mapping = ( ("bpy.types.gpencilsculptsettings.intersection_threshold*", "grease_pencil/modes/draw/tools/cutter.html#bpy-types-gpencilsculptsettings-intersection-threshold"), ("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"), ("bpy.types.lineartgpencilmodifier.use_intersection_mask*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-mask"), + ("bpy.types.lineartgpencilmodifier.use_invert_collection*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-invert-collection"), ("bpy.types.movietrackingsettings.use_keyframe_selection*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-keyframe-selection"), ("bpy.types.rendersettings.simplify_gpencil_antialiasing*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-antialiasing"), ("bpy.types.sequencertimelineoverlay.show_strip_duration*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-duration"), @@ -120,7 +120,6 @@ url_manual_mapping = ( ("bpy.types.brush.show_multiplane_scrape_planes_preview*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-show-multiplane-scrape-planes-preview"), ("bpy.types.brushgpencilsettings.eraser_strength_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-strength-factor"), ("bpy.types.cyclesmaterialsettings.volume_interpolation*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-volume-interpolation"), - ("bpy.types.cyclesrendersettings.debug_optix_curves_api*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-optix-curves-api"), ("bpy.types.cyclesrendersettings.denoising_input_passes*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoising-input-passes"), ("bpy.types.cyclesrendersettings.film_transparent_glass*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-glass"), ("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"), @@ -354,6 +353,7 @@ url_manual_mapping = ( ("bpy.types.toolsettings.use_keyframe_insert_auto*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-insert-auto"), ("bpy.types.viewlayer.use_pass_cryptomatte_object*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-object"), ("bpy.ops.armature.rigify_apply_selection_colors*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-apply-selection-colors"), + ("bpy.ops.ed.lib_id_generate_preview_from_object*", "editors/asset_browser.html#bpy-ops-ed-lib-id-generate-preview-from-object"), ("bpy.types.brushgpencilsettings.fill_layer_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-layer-mode"), ("bpy.types.brushgpencilsettings.random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-strength"), ("bpy.types.brushgpencilsettings.simplify_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-simplify-factor"), @@ -375,6 +375,7 @@ url_manual_mapping = ( ("bpy.types.freestylelinestyle.use_split_pattern*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-split-pattern"), ("bpy.types.freestylesettings.use_view_map_cache*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-view-map-cache"), ("bpy.types.geometrynodecurvehandletypeselection*", "modeling/geometry_nodes/curve/handle_type_selection.html#bpy-types-geometrynodecurvehandletypeselection"), + ("bpy.types.geometrynodeinputmeshvertexneighbors*", "modeling/geometry_nodes/mesh/vertex_neighbors.html#bpy-types-geometrynodeinputmeshvertexneighbors"), ("bpy.types.greasepencil.curve_edit_corner_angle*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-corner-angle"), ("bpy.types.lineartgpencilmodifier.source_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-source-camera"), ("bpy.types.lineartgpencilmodifier.use_face_mark*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark"), @@ -401,7 +402,6 @@ url_manual_mapping = ( ("bpy.types.brushgpencilsettings.use_fill_limit*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-use-fill-limit"), ("bpy.types.clothsettings.vertex_group_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-pressure"), ("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"), - ("bpy.types.cyclesrendersettings.debug_bvh_type*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-bvh-type"), ("bpy.types.cyclesrendersettings.fast_gi_method*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-fast-gi-method"), ("bpy.types.cyclesrendersettings.glossy_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-glossy-bounces"), ("bpy.types.cyclesrendersettings.volume_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-volume-bounces"), @@ -454,6 +454,7 @@ url_manual_mapping = ( ("bpy.types.cyclescamerasettings.panorama_type*", "render/cycles/object_settings/cameras.html#bpy-types-cyclescamerasettings-panorama-type"), ("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-camera"), ("bpy.types.cyclesrendersettings.film_exposure*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-exposure"), + ("bpy.types.cyclesrendersettings.sample_offset*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-sample-offset"), ("bpy.types.cyclesrendersettings.texture_limit*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-texture-limit"), ("bpy.types.cyclesrendersettings.use_denoising*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-use-denoising"), ("bpy.types.editbone.bbone_custom_handle_start*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-custom-handle-start"), @@ -479,6 +480,8 @@ url_manual_mapping = ( ("bpy.types.freestylelinestyle.use_dashed_line*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-dashed-line"), ("bpy.types.freestylelinestyle.use_same_object*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-same-object"), ("bpy.types.functionnodeinputspecialcharacters*", "modeling/geometry_nodes/text/special_characters.html#bpy-types-functionnodeinputspecialcharacters"), + ("bpy.types.geometrynodeinputmeshedgeneighbors*", "modeling/geometry_nodes/mesh/edge_neighbors.html#bpy-types-geometrynodeinputmeshedgeneighbors"), + ("bpy.types.geometrynodeinputmeshfaceneighbors*", "modeling/geometry_nodes/mesh/face_neighbors.html#bpy-types-geometrynodeinputmeshfaceneighbors"), ("bpy.types.gpencilsculptguide.reference_point*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-reference-point"), ("bpy.types.greasepencil.edit_curve_resolution*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-edit-curve-resolution"), ("bpy.types.linestylegeometrymodifier_2doffset*", "render/freestyle/view_layer/line_style/modifiers/geometry/2d_offset.html#bpy-types-linestylegeometrymodifier-2doffset"), @@ -491,6 +494,7 @@ url_manual_mapping = ( ("bpy.types.sequencertimelineoverlay.show_grid*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-grid"), ("bpy.types.sequencertoolsettings.overlap_mode*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-overlap-mode"), ("bpy.types.spaceclipeditor.show_green_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-green-channel"), + ("bpy.types.spacenodeoverlay.show_context_path*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-context-path"), ("bpy.types.spaceoutliner.show_restrict_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-restrict-column"), ("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"), ("bpy.types.spaceuveditor.display_stretch_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-display-stretch-type"), @@ -518,6 +522,7 @@ url_manual_mapping = ( ("bpy.types.freestylelineset.select_edge_mark*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-select-edge-mark"), ("bpy.types.freestylelinestyle.use_length_max*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-length-max"), ("bpy.types.freestylelinestyle.use_length_min*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-length-min"), + ("bpy.types.geometrynodeinputmeshedgevertices*", "modeling/geometry_nodes/mesh/edge_vertices.html#bpy-types-geometrynodeinputmeshedgevertices"), ("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"), ("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"), ("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"), @@ -613,6 +618,7 @@ url_manual_mapping = ( ("bpy.types.brush.surface_smooth_iterations*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-iterations"), ("bpy.types.brushgpencilsettings.pen_jitter*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-jitter"), ("bpy.types.brushgpencilsettings.show_lasso*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-show-lasso"), + ("bpy.types.compositornodeconvertcolorspace*", "compositing/types/converter/color_space.html#bpy-types-compositornodeconvertcolorspace"), ("bpy.types.cyclescurverendersettings.shape*", "render/cycles/render_settings/hair.html#bpy-types-cyclescurverendersettings-shape"), ("bpy.types.cyclesrendersettings.ao_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-ao-bounces"), ("bpy.types.cyclesrendersettings.time_limit*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-time-limit"), @@ -709,7 +715,9 @@ url_manual_mapping = ( ("bpy.types.geometrynodealigneulertovector*", "modeling/geometry_nodes/utilities/align_euler_to_vector.html#bpy-types-geometrynodealigneulertovector"), ("bpy.types.geometrynodeattributestatistic*", "modeling/geometry_nodes/attribute/attribute_statistic.html#bpy-types-geometrynodeattributestatistic"), ("bpy.types.geometrynodecurvequadrilateral*", "modeling/geometry_nodes/curve_primitives/quadrilateral.html#bpy-types-geometrynodecurvequadrilateral"), + ("bpy.types.geometrynodegeometrytoinstance*", "modeling/geometry_nodes/geometry/geometry_to_instance.html#bpy-types-geometrynodegeometrytoinstance"), ("bpy.types.geometrynodeinputmaterialindex*", "modeling/geometry_nodes/material/material_index.html#bpy-types-geometrynodeinputmaterialindex"), + ("bpy.types.geometrynodeinputmeshedgeangle*", "modeling/geometry_nodes/mesh/edge_angle.html#bpy-types-geometrynodeinputmeshedgeangle"), ("bpy.types.geometrynodeseparatecomponents*", "modeling/geometry_nodes/geometry/separate_components.html#bpy-types-geometrynodeseparatecomponents"), ("bpy.types.geometrynodesubdivisionsurface*", "modeling/geometry_nodes/mesh/subdivision_surface.html#bpy-types-geometrynodesubdivisionsurface"), ("bpy.types.geometrynodetranslateinstances*", "modeling/geometry_nodes/instances/translate_instances.html#bpy-types-geometrynodetranslateinstances"), @@ -789,6 +797,7 @@ url_manual_mapping = ( ("bpy.types.freestylesettings.use_culling*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-culling"), ("bpy.types.geometrynodeendpointselection*", "modeling/geometry_nodes/curve/endpoint_selection.html#bpy-types-geometrynodeendpointselection"), ("bpy.types.geometrynodegeometryproximity*", "modeling/geometry_nodes/geometry/geometry_proximity.html#bpy-types-geometrynodegeometryproximity"), + ("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/face_area.html#bpy-types-geometrynodeinputmeshfacearea"), ("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"), ("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"), ("bpy.types.geometrynodetransferattribute*", "modeling/geometry_nodes/attribute/transfer_attribute.html#bpy-types-geometrynodetransferattribute"), @@ -818,6 +827,7 @@ url_manual_mapping = ( ("bpy.types.toolsettings.mesh_select_mode*", "modeling/meshes/selecting/introduction.html#bpy-types-toolsettings-mesh-select-mode"), ("bpy.types.toolsettings.use_snap_project*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-project"), ("bpy.types.transformorientationslot.type*", "editors/3dview/controls/orientation.html#bpy-types-transformorientationslot-type"), + ("bpy.types.unitsettings.temperature_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-temperature-unit"), ("bpy.types.vertexweightproximitymodifier*", "modeling/modifiers/modify/weight_proximity.html#bpy-types-vertexweightproximitymodifier"), ("bpy.types.view3doverlay.show_wireframes*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-wireframes"), ("bpy.types.view3dshading.background_type*", "editors/3dview/display/shading.html#bpy-types-view3dshading-background-type"), @@ -875,6 +885,7 @@ url_manual_mapping = ( ("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"), ("bpy.types.toolsettings.snap_uv_element*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-snap-uv-element"), ("bpy.types.toolsettings.use_snap_rotate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-rotate"), + ("bpy.types.unitsettings.system_rotation*", "scene_layout/scene/properties.html#bpy-types-unitsettings-system-rotation"), ("bpy.types.view3doverlay.display_handle*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-display-handle"), ("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"), ("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-editable-toggle"), @@ -919,11 +930,15 @@ url_manual_mapping = ( ("bpy.types.freestylelineset.visibility*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-visibility"), ("bpy.types.freestylelinestyle.chaining*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-chaining"), ("bpy.types.freestylelinestyle.sort_key*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-sort-key"), + ("bpy.types.geometrynodeaccumulatefield*", "modeling/geometry_nodes/utilities/accumulate_field.html#bpy-types-geometrynodeaccumulatefield"), ("bpy.types.geometrynodecurvesethandles*", "modeling/geometry_nodes/curve/set_handle_type.html#bpy-types-geometrynodecurvesethandles"), ("bpy.types.geometrynodecurvesplinetype*", "modeling/geometry_nodes/curve/set_spline_type.html#bpy-types-geometrynodecurvesplinetype"), + ("bpy.types.geometrynodeinputmeshisland*", "modeling/geometry_nodes/mesh/mesh_island.html#bpy-types-geometrynodeinputmeshisland"), + ("bpy.types.geometrynodemergebydistance*", "modeling/geometry_nodes/geometry/merge_by_distance.html#bpy-types-geometrynodemergebydistance"), ("bpy.types.geometrynodereplacematerial*", "modeling/geometry_nodes/material/replace_material.html#bpy-types-geometrynodereplacematerial"), ("bpy.types.geometrynoderotateinstances*", "modeling/geometry_nodes/instances/rotate_instances.html#bpy-types-geometrynoderotateinstances"), ("bpy.types.geometrynodesetsplinecyclic*", "modeling/geometry_nodes/curve/set_spline_cyclic.html#bpy-types-geometrynodesetsplinecyclic"), + ("bpy.types.geometrynodesplineparameter*", "modeling/geometry_nodes/curve/spline_parameter.html#bpy-types-geometrynodesplineparameter"), ("bpy.types.gpencillayer.use_mask_layer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-mask-layer"), ("bpy.types.greasepencil.use_curve_edit*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-curve-edit"), ("bpy.types.imagepaint.screen_grab_size*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-screen-grab-size"), @@ -993,9 +1008,9 @@ url_manual_mapping = ( ("bpy.types.fluidflowsettings.use_flow*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-flow"), ("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierfunctiongenerator"), ("bpy.types.geometrynodecollectioninfo*", "modeling/geometry_nodes/input/collection_info.html#bpy-types-geometrynodecollectioninfo"), - ("bpy.types.geometrynodecurveparameter*", "modeling/geometry_nodes/curve/curve_parameter.html#bpy-types-geometrynodecurveparameter"), ("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/delete_geometry.html#bpy-types-geometrynodedeletegeometry"), ("bpy.types.geometrynodeinputcurvetilt*", "modeling/geometry_nodes/curve/curve_tilt.html#bpy-types-geometrynodeinputcurvetilt"), + ("bpy.types.geometrynodeinputscenetime*", "modeling/geometry_nodes/input/scene_time.html#bpy-types-geometrynodeinputscenetime"), ("bpy.types.geometrynodepointstovolume*", "modeling/geometry_nodes/point/points_to_volume.html#bpy-types-geometrynodepointstovolume"), ("bpy.types.geometrynodescaleinstances*", "modeling/geometry_nodes/instances/scale_instances.html#bpy-types-geometrynodescaleinstances"), ("bpy.types.geometrynodesetcurveradius*", "modeling/geometry_nodes/curve/set_curve_radius.html#bpy-types-geometrynodesetcurveradius"), @@ -1075,7 +1090,6 @@ url_manual_mapping = ( ("bpy.types.fluidflowsettings.density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-density"), ("bpy.types.freestylelineset.qi_start*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-qi-start"), ("bpy.types.freestylelinestyle.rounds*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-rounds"), - ("bpy.types.functionnodecomparefloats*", "modeling/geometry_nodes/utilities/compare_floats.html#bpy-types-functionnodecomparefloats"), ("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/curve_to_points.html#bpy-types-geometrynodecurvetopoints"), ("bpy.types.geometrynodeinputmaterial*", "modeling/geometry_nodes/input/material.html#bpy-types-geometrynodeinputmaterial"), ("bpy.types.geometrynodeinputposition*", "modeling/geometry_nodes/input/position.html#bpy-types-geometrynodeinputposition"), @@ -1083,6 +1097,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodemeshicosphere*", "modeling/geometry_nodes/mesh_primitives/icosphere.html#bpy-types-geometrynodemeshicosphere"), ("bpy.types.geometrynodereplacestring*", "modeling/geometry_nodes/text/replace_string.html#bpy-types-geometrynodereplacestring"), ("bpy.types.geometrynoderesamplecurve*", "modeling/geometry_nodes/curve/resample_curve.html#bpy-types-geometrynoderesamplecurve"), + ("bpy.types.geometrynodescaleelements*", "modeling/geometry_nodes/mesh/scale_elements.html#bpy-types-geometrynodescaleelements"), ("bpy.types.geometrynodesubdividemesh*", "modeling/geometry_nodes/mesh/subdivide_mesh.html#bpy-types-geometrynodesubdividemesh"), ("bpy.types.geometrynodevaluetostring*", "modeling/geometry_nodes/text/value_to_string.html#bpy-types-geometrynodevaluetostring"), ("bpy.types.keyframe.handle_left_type*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-left-type"), @@ -1106,6 +1121,7 @@ url_manual_mapping = ( ("bpy.types.shadernodebsdftranslucent*", "render/shader_nodes/shader/translucent.html#bpy-types-shadernodebsdftranslucent"), ("bpy.types.shadernodebsdftransparent*", "render/shader_nodes/shader/transparent.html#bpy-types-shadernodebsdftransparent"), ("bpy.types.shadernodevectortransform*", "render/shader_nodes/vector/transform.html#bpy-types-shadernodevectortransform"), + ("bpy.types.shrinkwrapgpencilmodifier*", "grease_pencil/modifiers/deform/shrinkwrap.html#bpy-types-shrinkwrapgpencilmodifier"), ("bpy.types.spaceclipeditor.show_grid*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-grid"), ("bpy.types.spaceoutliner.filter_text*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-text"), ("bpy.types.spacetexteditor.find_text*", "editors/text_editor.html#bpy-types-spacetexteditor-find-text"), @@ -1114,6 +1130,8 @@ url_manual_mapping = ( ("bpy.types.spaceuveditor.lock_bounds*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-lock-bounds"), ("bpy.types.spline.tilt_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-tilt-interpolation"), ("bpy.types.transformorientation.name*", "editors/3dview/controls/orientation.html#bpy-types-transformorientation-name"), + ("bpy.types.unitsettings.scale_length*", "scene_layout/scene/properties.html#bpy-types-unitsettings-scale-length"), + ("bpy.types.unitsettings.use_separate*", "scene_layout/scene/properties.html#bpy-types-unitsettings-use-separate"), ("bpy.types.viewlayer.use_motion_blur*", "render/layers/introduction.html#bpy-types-viewlayer-use-motion-blur"), ("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"), ("bpy.types.worldmistsettings.falloff*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-falloff"), @@ -1146,13 +1164,14 @@ url_manual_mapping = ( ("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"), ("bpy.types.assetmetadata.active_tag*", "editors/asset_browser.html#bpy-types-assetmetadata-active-tag"), ("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"), + ("bpy.types.bakesettings.margin_type*", "render/cycles/baking.html#bpy-types-bakesettings-margin-type"), ("bpy.types.bone.use_relative_parent*", "animation/armatures/bones/properties/relations.html#bpy-types-bone-use-relative-parent"), ("bpy.types.brush.auto_smooth_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-auto-smooth-factor"), ("bpy.types.brush.smooth_deform_type*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-smooth-deform-type"), ("bpy.types.brush.use_connected_only*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-use-connected-only"), ("bpy.types.brush.use_cursor_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-cursor-overlay"), ("bpy.types.camera.show_passepartout*", "render/cameras.html#bpy-types-camera-show-passepartout"), - ("bpy.types.collection.lineart_usage*", "scene_layout/collections/properties.html#bpy-types-collection-lineart-usage"), + ("bpy.types.collection.lineart_usage*", "scene_layout/collections/collections.html#bpy-types-collection-lineart-usage"), ("bpy.types.colormanagedviewsettings*", "render/color_management.html#bpy-types-colormanagedviewsettings"), ("bpy.types.compositornodebokehimage*", "compositing/types/input/bokeh_image.html#bpy-types-compositornodebokehimage"), ("bpy.types.compositornodecolormatte*", "compositing/types/matte/color_key.html#bpy-types-compositornodecolormatte"), @@ -1168,6 +1187,7 @@ url_manual_mapping = ( ("bpy.types.freestylelineset.exclude*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-exclude"), ("bpy.types.freestylelinestyle.alpha*", "render/freestyle/view_layer/line_style/alpha.html#bpy-types-freestylelinestyle-alpha"), ("bpy.types.freestylelinestyle.color*", "render/freestyle/view_layer/line_style/color.html#bpy-types-freestylelinestyle-color"), + ("bpy.types.geometrynodefieldatindex*", "modeling/geometry_nodes/utilities/field_at_index.html#bpy-types-geometrynodefieldatindex"), ("bpy.types.geometrynodeinputtangent*", "modeling/geometry_nodes/curve/curve_tangent.html#bpy-types-geometrynodeinputtangent"), ("bpy.types.geometrynodejoingeometry*", "modeling/geometry_nodes/geometry/join_geometry.html#bpy-types-geometrynodejoingeometry"), ("bpy.types.geometrynodemeshcylinder*", "modeling/geometry_nodes/mesh_primitives/cylinder.html#bpy-types-geometrynodemeshcylinder"), @@ -1203,6 +1223,7 @@ url_manual_mapping = ( ("bpy.types.thicknessgpencilmodifier*", "grease_pencil/modifiers/deform/thickness.html#bpy-types-thicknessgpencilmodifier"), ("bpy.types.toolsettings.snap_target*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-target"), ("bpy.types.transformcacheconstraint*", "animation/constraints/transform/transform_cache.html#bpy-types-transformcacheconstraint"), + ("bpy.types.unitsettings.length_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-length-unit"), ("bpy.types.vertexweighteditmodifier*", "modeling/modifiers/modify/weight_edit.html#bpy-types-vertexweighteditmodifier"), ("bpy.types.volumedisplay.slice_axis*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-axis"), ("bpy.ops.anim.channels_clean_empty*", "editors/nla/editing.html#bpy-ops-anim-channels-clean-empty"), @@ -1225,7 +1246,7 @@ url_manual_mapping = ( ("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"), ("bpy.ops.poselib.create_pose_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-create-pose-asset"), ("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"), - ("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"), + ("bpy.ops.render.play_rendered_anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"), ("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"), ("bpy.ops.sequencer.image_strip_add*", "video_editing/sequencer/strips/image.html#bpy-ops-sequencer-image-strip-add"), ("bpy.ops.sequencer.movie_strip_add*", "video_editing/sequencer/strips/movie.html#bpy-ops-sequencer-movie-strip-add"), @@ -1249,6 +1270,7 @@ url_manual_mapping = ( ("bpy.types.compositornodemovieclip*", "compositing/types/input/movie_clip.html#bpy-types-compositornodemovieclip"), ("bpy.types.compositornodenormalize*", "compositing/types/vector/normalize.html#bpy-types-compositornodenormalize"), ("bpy.types.compositornodepremulkey*", "compositing/types/converter/alpha_convert.html#bpy-types-compositornodepremulkey"), + ("bpy.types.compositornodescenetime*", "compositing/types/input/scene_time.html#bpy-types-compositornodescenetime"), ("bpy.types.compositornodestabilize*", "compositing/types/distort/stabilize_2d.html#bpy-types-compositornodestabilize"), ("bpy.types.compositornodetransform*", "compositing/types/distort/transform.html#bpy-types-compositornodetransform"), ("bpy.types.compositornodetranslate*", "compositing/types/distort/translate.html#bpy-types-compositornodetranslate"), @@ -1269,6 +1291,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodecurvelength*", "modeling/geometry_nodes/curve/curve_length.html#bpy-types-geometrynodecurvelength"), ("bpy.types.geometrynodecurvespiral*", "modeling/geometry_nodes/curve_primitives/curve_spiral.html#bpy-types-geometrynodecurvespiral"), ("bpy.types.geometrynodecurvetomesh*", "modeling/geometry_nodes/curve/curve_to_mesh.html#bpy-types-geometrynodecurvetomesh"), + ("bpy.types.geometrynodeextrudemesh*", "modeling/geometry_nodes/mesh/extrude_mesh.html#bpy-types-geometrynodeextrudemesh"), ("bpy.types.geometrynodefilletcurve*", "modeling/geometry_nodes/curve/fillet_curve.html#bpy-types-geometrynodefilletcurve"), ("bpy.types.geometrynodeinputnormal*", "modeling/geometry_nodes/input/normal.html#bpy-types-geometrynodeinputnormal"), ("bpy.types.geometrynodeinputradius*", "modeling/geometry_nodes/input/radius.html#bpy-types-geometrynodeinputradius"), @@ -1328,6 +1351,7 @@ url_manual_mapping = ( ("bpy.ops.mesh.primitive_plane_add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-plane-add"), ("bpy.ops.mesh.primitive_torus_add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-torus-add"), ("bpy.ops.mesh.select_non_manifold*", "modeling/meshes/selecting/all_by_trait.html#bpy-ops-mesh-select-non-manifold"), + ("bpy.ops.object.attribute_convert*", "modeling/geometry_nodes/attributes_reference.html#bpy-ops-object-attribute-convert"), ("bpy.ops.object.constraints_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-clear"), ("bpy.ops.object.quadriflow_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-quadriflow-remesh"), ("bpy.ops.object.vertex_group_copy*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy"), @@ -1384,6 +1408,7 @@ url_manual_mapping = ( ("bpy.types.freestylelinestyle.gap*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-gap"), ("bpy.types.freestylesettings.mode*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-mode"), ("bpy.types.geometrynodeconvexhull*", "modeling/geometry_nodes/geometry/convex_hull.html#bpy-types-geometrynodeconvexhull"), + ("bpy.types.geometrynodedomainsize*", "modeling/geometry_nodes/attribute/domain_size.html#bpy-types-geometrynodedomainsize"), ("bpy.types.geometrynodefloattoint*", "modeling/geometry_nodes/utilities/float_to_integer.html#bpy-types-geometrynodefloattoint"), ("bpy.types.geometrynodeinputcolor*", "modeling/geometry_nodes/input/color.html#bpy-types-geometrynodeinputcolor"), ("bpy.types.geometrynodeinputindex*", "modeling/geometry_nodes/input/input_index.html#bpy-types-geometrynodeinputindex"), @@ -1414,6 +1439,8 @@ url_manual_mapping = ( ("bpy.types.sound.use_memory_cache*", "video_editing/sequencer/sidebar/strip.html#bpy-types-sound-use-memory-cache"), ("bpy.types.spaceview3d.show_gizmo*", "editors/3dview/display/gizmo.html#bpy-types-spaceview3d-show-gizmo"), ("bpy.types.texturegpencilmodifier*", "grease_pencil/modifiers/modify/texture_mapping.html#bpy-types-texturegpencilmodifier"), + ("bpy.types.unitsettings.mass_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-mass-unit"), + ("bpy.types.unitsettings.time_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-time-unit"), ("bpy.types.volumedisplacemodifier*", "modeling/modifiers/deform/volume_displace.html#bpy-types-volumedisplacemodifier"), ("bpy.types.volumerender.step_size*", "modeling/volumes/properties.html#bpy-types-volumerender-step-size"), ("bpy.types.weightednormalmodifier*", "modeling/modifiers/modify/weighted_normal.html#bpy-types-weightednormalmodifier"), @@ -1431,6 +1458,7 @@ url_manual_mapping = ( ("bpy.ops.gpencil.stroke_caps_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-caps-set"), ("bpy.ops.gpencil.stroke_separate*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-separate"), ("bpy.ops.gpencil.stroke_simplify*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify"), + ("bpy.ops.graph.blend_to_neighbor*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-blend-to-neighbor"), ("bpy.ops.graph.snap_cursor_value*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-snap-cursor-value"), ("bpy.ops.image.save_all_modified*", "editors/image/editing.html#bpy-ops-image-save-all-modified"), ("bpy.ops.mesh.extrude_edges_move*", "modeling/meshes/editing/edge/extrude_edges.html#bpy-ops-mesh-extrude-edges-move"), @@ -1443,6 +1471,7 @@ url_manual_mapping = ( ("bpy.ops.mesh.subdivide_edgering*", "modeling/meshes/editing/edge/subdivide_edge_ring.html#bpy-ops-mesh-subdivide-edgering"), ("bpy.ops.node.hide_socket_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-hide-socket-toggle"), ("bpy.ops.node.tree_socket_remove*", "interface/controls/nodes/groups.html#bpy-ops-node-tree-socket-remove"), + ("bpy.ops.object.attribute_remove*", "modeling/geometry_nodes/attributes_reference.html#bpy-ops-object-attribute-remove"), ("bpy.ops.object.constraints_copy*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraints-copy"), ("bpy.ops.object.gpencil_modifier*", "grease_pencil/modifiers/index.html#bpy-ops-object-gpencil-modifier"), ("bpy.ops.object.make_links_scene*", "scene_layout/object/editing/link_transfer/link_scene.html#bpy-ops-object-make-links-scene"), @@ -1505,6 +1534,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodecurvestar*", "modeling/geometry_nodes/curve_primitives/star.html#bpy-types-geometrynodecurvestar"), ("bpy.types.geometrynodeedgesplit*", "modeling/geometry_nodes/mesh/split_edges.html#bpy-types-geometrynodeedgesplit"), ("bpy.types.geometrynodefillcurve*", "modeling/geometry_nodes/curve/fill_curve.html#bpy-types-geometrynodefillcurve"), + ("bpy.types.geometrynodeflipfaces*", "modeling/geometry_nodes/mesh/flip_faces.html#bpy-types-geometrynodeflipfaces"), ("bpy.types.geometrynodetransform*", "modeling/geometry_nodes/geometry/transform.html#bpy-types-geometrynodetransform"), ("bpy.types.geometrynodetrimcurve*", "modeling/geometry_nodes/curve/trim_curve.html#bpy-types-geometrynodetrimcurve"), ("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"), @@ -1548,6 +1578,7 @@ url_manual_mapping = ( ("bpy.ops.curve.switch_direction*", "modeling/curves/editing/segments.html#bpy-ops-curve-switch-direction"), ("bpy.ops.gpencil.duplicate_move*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-duplicate-move"), ("bpy.ops.gpencil.stroke_arrange*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-arrange"), + ("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"), ("bpy.ops.mesh.bridge-edge-loops*", "modeling/meshes/editing/edge/bridge_edge_loops.html#bpy-ops-mesh-bridge-edge-loops"), ("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"), ("bpy.ops.mesh.loop_multi_select*", "modeling/meshes/selecting/loops.html#bpy-ops-mesh-loop-multi-select"), @@ -1612,6 +1643,7 @@ url_manual_mapping = ( ("bpy.types.motionpath.frame_end*", "animation/motion_paths.html#bpy-types-motionpath-frame-end"), ("bpy.types.noisegpencilmodifier*", "grease_pencil/modifiers/deform/noise.html#bpy-types-noisegpencilmodifier"), ("bpy.types.object.hide_viewport*", "scene_layout/object/properties/visibility.html#bpy-types-object-hide-viewport"), + ("bpy.types.object.rotation_mode*", "scene_layout/object/properties/transforms.html#bpy-types-object-rotation-mode"), ("bpy.types.object.show_in_front*", "scene_layout/object/properties/display.html#bpy-types-object-show-in-front"), ("bpy.types.posebone.rigify_type*", "addons/rigging/rigify/rig_types/index.html#bpy-types-posebone-rigify-type"), ("bpy.types.preferencesfilepaths*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths"), @@ -1714,6 +1746,7 @@ url_manual_mapping = ( ("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"), ("bpy.types.dashgpencilmodifier*", "grease_pencil/modifiers/generate/dash.html#bpy-types-dashgpencilmodifier"), ("bpy.types.fluiddomainsettings*", "physics/fluid/type/domain/index.html#bpy-types-fluiddomainsettings"), + ("bpy.types.functionnodecompare*", "modeling/geometry_nodes/utilities/compare.html#bpy-types-functionnodecompare"), ("bpy.types.geometrynodeboolean*", "modeling/geometry_nodes/input/boolean.html#bpy-types-geometrynodeboolean"), ("bpy.types.geometrynodeinputid*", "modeling/geometry_nodes/input/id.html#bpy-types-geometrynodeinputid"), ("bpy.types.geometrynodeinteger*", "modeling/geometry_nodes/input/integer.html#bpy-types-geometrynodeinteger"), @@ -1740,6 +1773,7 @@ url_manual_mapping = ( ("bpy.types.shadernodelightpath*", "render/shader_nodes/input/light_path.html#bpy-types-shadernodelightpath"), ("bpy.types.shadernodemixshader*", "render/shader_nodes/shader/mix.html#bpy-types-shadernodemixshader"), ("bpy.types.shadernodenormalmap*", "render/shader_nodes/vector/normal_map.html#bpy-types-shadernodenormalmap"), + ("bpy.types.shadernodepointinfo*", "render/shader_nodes/input/point_info.html#bpy-types-shadernodepointinfo"), ("bpy.types.shadernodewireframe*", "render/shader_nodes/input/wireframe.html#bpy-types-shadernodewireframe"), ("bpy.types.spacesequenceeditor*", "video_editing/index.html#bpy-types-spacesequenceeditor"), ("bpy.types.spline.resolution_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-resolution-u"), @@ -1752,6 +1786,7 @@ url_manual_mapping = ( ("bpy.types.tintgpencilmodifier*", "grease_pencil/modifiers/color/tint.html#bpy-types-tintgpencilmodifier"), ("bpy.types.transformconstraint*", "animation/constraints/transform/transformation.html#bpy-types-transformconstraint"), ("bpy.types.triangulatemodifier*", "modeling/modifiers/generate/triangulate.html#bpy-types-triangulatemodifier"), + ("bpy.types.unitsettings.system*", "scene_layout/scene/properties.html#bpy-types-unitsettings-system"), ("bpy.types.viewlayer.use_solid*", "render/layers/introduction.html#bpy-types-viewlayer-use-solid"), ("bpy.types.volume.frame_offset*", "modeling/volumes/properties.html#bpy-types-volume-frame-offset"), ("bpy.types.windowmanager.addon*", "editors/preferences/addons.html#bpy-types-windowmanager-addon"), @@ -1784,6 +1819,7 @@ url_manual_mapping = ( ("bpy.ops.node.node_copy_color*", "interface/controls/nodes/sidebar.html#bpy-ops-node-node-copy-color"), ("bpy.ops.node.read_viewlayers*", "interface/controls/nodes/editing.html#bpy-ops-node-read-viewlayers"), ("bpy.ops.node.tree_socket_add*", "interface/controls/nodes/groups.html#bpy-ops-node-tree-socket-add"), + ("bpy.ops.object.attribute_add*", "modeling/geometry_nodes/attributes_reference.html#bpy-ops-object-attribute-add"), ("bpy.ops.object.data_transfer*", "scene_layout/object/editing/link_transfer/transfer_mesh_data.html#bpy-ops-object-data-transfer"), ("bpy.ops.object.modifier_copy*", "modeling/modifiers/introduction.html#bpy-ops-object-modifier-copy"), ("bpy.ops.object.select_camera*", "scene_layout/object/selecting.html#bpy-ops-object-select-camera"), @@ -1815,12 +1851,12 @@ url_manual_mapping = ( ("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"), ("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"), ("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"), - ("bpy.types.compositornodecomb*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodecomb"), + ("bpy.types.compositornodecomb*", "compositing/types/converter/combine_separate.html#bpy-types-compositornodecomb"), ("bpy.types.compositornodecrop*", "compositing/types/distort/crop.html#bpy-types-compositornodecrop"), ("bpy.types.compositornodeflip*", "compositing/types/distort/flip.html#bpy-types-compositornodeflip"), ("bpy.types.compositornodemask*", "compositing/types/input/mask.html#bpy-types-compositornodemask"), ("bpy.types.compositornodemath*", "compositing/types/converter/math.html#bpy-types-compositornodemath"), - ("bpy.types.compositornodetime*", "compositing/types/input/time.html#bpy-types-compositornodetime"), + ("bpy.types.compositornodetime*", "compositing/types/input/time_curve.html#bpy-types-compositornodetime"), ("bpy.types.constraint.enabled*", "animation/constraints/interface/header.html#bpy-types-constraint-enabled"), ("bpy.types.curve.bevel_object*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-object"), ("bpy.types.curve.resolution_u*", "modeling/curves/properties/shape.html#bpy-types-curve-resolution-u"), @@ -1888,6 +1924,7 @@ url_manual_mapping = ( ("bpy.ops.curve.smooth_weight*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-weight"), ("bpy.ops.file.pack_libraries*", "files/blend/packed_data.html#bpy-ops-file-pack-libraries"), ("bpy.ops.font.change_spacing*", "modeling/texts/editing.html#bpy-ops-font-change-spacing"), + ("bpy.ops.gpencil.layer_merge*", "grease_pencil/properties/layers.html#bpy-ops-gpencil-layer-merge"), ("bpy.ops.gpencil.stroke_flip*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-flip"), ("bpy.ops.gpencil.stroke_join*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-join"), ("bpy.ops.gpencil.stroke_trim*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-trim"), @@ -1945,7 +1982,7 @@ url_manual_mapping = ( ("bpy.types.collisionmodifier*", "physics/collision.html#bpy-types-collisionmodifier"), ("bpy.types.collisionsettings*", "physics/collision.html#bpy-types-collisionsettings"), ("bpy.types.compositornodergb*", "compositing/types/input/rgb.html#bpy-types-compositornodergb"), - ("bpy.types.compositornodesep*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodesep"), + ("bpy.types.compositornodesep*", "compositing/types/converter/combine_separate.html#bpy-types-compositornodesep"), ("bpy.types.curve.bevel_depth*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-depth"), ("bpy.types.curve.use_stretch*", "modeling/curves/properties/shape.html#bpy-types-curve-use-stretch"), ("bpy.types.edgesplitmodifier*", "modeling/modifiers/generate/edge_split.html#bpy-types-edgesplitmodifier"), @@ -2168,6 +2205,7 @@ url_manual_mapping = ( ("bpy.types.floorconstraint*", "animation/constraints/relationship/floor.html#bpy-types-floorconstraint"), ("bpy.types.fmodifiercycles*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiercycles"), ("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierlimits"), + ("bpy.types.geometrynodearc*", "modeling/geometry_nodes/curve_primitives/arc.html#bpy-types-geometrynodearc"), ("bpy.types.imagepaint.mode*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-mode"), ("bpy.types.latticemodifier*", "modeling/modifiers/deform/lattice.html#bpy-types-latticemodifier"), ("bpy.types.materiallineart*", "render/materials/line_art.html#bpy-types-materiallineart"), @@ -2285,6 +2323,7 @@ url_manual_mapping = ( ("bpy.ops.fluid.free_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-ops-fluid-free-mesh"), ("bpy.ops.font.select_all*", "modeling/texts/selecting.html#bpy-ops-font-select-all"), ("bpy.ops.gpencil.convert*", "grease_pencil/modes/object/convert_to_geometry.html#bpy-ops-gpencil-convert"), + ("bpy.ops.graph.breakdown*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-breakdown"), ("bpy.ops.mask.parent_set*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-set"), ("bpy.ops.mask.select_all*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-all"), ("bpy.ops.mask.select_box*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-box"), @@ -2471,6 +2510,7 @@ url_manual_mapping = ( ("bpy.ops.sculpt.expand*", "sculpt_paint/sculpting/editing/mask.html#bpy-ops-sculpt-expand"), ("bpy.ops.view3d.select*", "editors/3dview/selecting.html#bpy-ops-view3d-select"), ("bpy.ops.wm.debug_menu*", "advanced/operators.html#bpy-ops-wm-debug-menu"), + ("bpy.ops.wm.obj_export*", "files/import_export/obj.html#bpy-ops-wm-obj-export"), ("bpy.ops.wm.properties*", "files/data_blocks.html#bpy-ops-wm-properties"), ("bpy.ops.wm.usd_export*", "files/import_export/usd.html#bpy-ops-wm-usd-export"), ("bpy.types.addsequence*", "video_editing/sequencer/strips/effects/add.html#bpy-types-addsequence"), @@ -2574,6 +2614,7 @@ url_manual_mapping = ( ("bpy.types.node.name*", "interface/controls/nodes/sidebar.html#bpy-types-node-name"), ("bpy.types.nodeframe*", "interface/controls/nodes/frame.html#bpy-types-nodeframe"), ("bpy.types.nodegroup*", "interface/controls/nodes/groups.html#bpy-types-nodegroup"), + ("bpy.types.scene.muv*", "addons/uv/magic_uv.html#bpy-types-scene-muv"), ("bpy.types.spotlight*", "render/lights/light_object.html#bpy-types-spotlight"), ("bpy.types.textcurve*", "modeling/texts/index.html#bpy-types-textcurve"), ("bpy.types.udimtiles*", "modeling/meshes/uv/workflows/udims.html#bpy-types-udimtiles"), @@ -2709,6 +2750,7 @@ url_manual_mapping = ( ("bpy.ops.render*", "render/index.html#bpy-ops-render"), ("bpy.ops.script*", "advanced/scripting/index.html#bpy-ops-script"), ("bpy.ops.sculpt*", "sculpt_paint/sculpting/index.html#bpy-ops-sculpt"), + ("bpy.ops.uv.muv*", "addons/uv/magic_uv.html#bpy-ops-uv-muv"), ("bpy.ops.uv.pin*", "modeling/meshes/uv/editing.html#bpy-ops-uv-pin"), ("bpy.ops.uv.rip*", "modeling/meshes/uv/tools/rip.html#bpy-ops-uv-rip"), ("bpy.ops.view3d*", "editors/3dview/index.html#bpy-ops-view3d"), diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 6980f07eba4..bb2491d7720 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -177,7 +177,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): col.label(text="which was replaced by the Asset Browser.") url = self.get_manual_url() - col.operator('wm.url_open', text="More Info", icon="URL").url = url + col.operator("wm.url_open", text="More Info", icon='URL').url = url layout.separator() @@ -188,12 +188,12 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): col.template_ID(ob, "pose_library", new="poselib.new", unlink="poselib.unlink") if poselib: - if hasattr(bpy.types, 'POSELIB_OT_convert_old_object_poselib'): - col.operator('poselib.convert_old_object_poselib', - text="Convert to Pose Assets", icon="ASSET_MANAGER") + if hasattr(bpy.types, "POSELIB_OT_convert_old_object_poselib"): + col.operator("poselib.convert_old_object_poselib", + text="Convert to Pose Assets", icon='ASSET_MANAGER') else: - col.label(text="Enable the Pose Library add-on to convert", icon="ERROR") - col.label(text="this legacy pose library to pose assets.", icon="BLANK1") + col.label(text="Enable the Pose Library add-on to convert", icon='ERROR') + col.label(text="this legacy pose library to pose assets.", icon='BLANK1') # Put the deprecated stuff in its own sub-layout. @@ -202,7 +202,10 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): # warning about poselib being in an invalid state if poselib.fcurves and not poselib.pose_markers: - dep_layout.label(icon='ERROR', text="Error: Potentially corrupt library, run 'Sanitize' operator to fix") + dep_layout.label( + icon='ERROR', + text="Error: Potentially corrupt library, run 'Sanitize' operator to fix", + ) # list of poses in pose library row = dep_layout.row() diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 83e797583ad..44d764f1a2d 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # <pep8 compliant> -from bpy.types import Panel, UIList +from bpy.types import Menu, Panel, UIList class VIEWLAYER_UL_aov(UIList): @@ -138,7 +138,7 @@ class ViewLayerAOVPanel(ViewLayerButtonsPanel, Panel): row = layout.row() col = row.column() col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer, - "aovs", view_layer, "active_aov_index", rows=2) + "aovs", view_layer, "active_aov_index", rows=3) col = row.column() sub = col.column(align=True) @@ -187,6 +187,16 @@ class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel, Panel): COMPAT_ENGINES = {'BLENDER_EEVEE'} +class VIEWLAYER_MT_lightgroup_sync(Menu): + bl_label = "Lightgroup Sync" + + def draw(self, _context): + layout = self.layout + + layout.operator("scene.view_layer_add_used_lightgroups", icon='ADD') + layout.operator("scene.view_layer_remove_unused_lightgroups", icon='REMOVE') + + class ViewLayerLightgroupsPanel(ViewLayerButtonsPanel, Panel): bl_label = "Light Groups" @@ -201,12 +211,14 @@ class ViewLayerLightgroupsPanel(ViewLayerButtonsPanel, Panel): row = layout.row() col = row.column() col.template_list("UI_UL_list", "lightgroups", view_layer, - "lightgroups", view_layer, "active_lightgroup_index", rows=2) + "lightgroups", view_layer, "active_lightgroup_index", rows=3) col = row.column() sub = col.column(align=True) sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="") sub.operator("scene.view_layer_remove_lightgroup", icon='REMOVE', text="") + sub.separator() + sub.menu("VIEWLAYER_MT_lightgroup_sync", icon='DOWNARROW_HLT', text="") class VIEWLAYER_PT_layer_passes_lightgroups(ViewLayerLightgroupsPanel): @@ -215,6 +227,7 @@ class VIEWLAYER_PT_layer_passes_lightgroups(ViewLayerLightgroupsPanel): classes = ( + VIEWLAYER_MT_lightgroup_sync, VIEWLAYER_PT_layer, VIEWLAYER_PT_layer_passes, VIEWLAYER_PT_eevee_layer_passes_data, diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 785a841a0e6..1dd50c979e2 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -1453,66 +1453,57 @@ class IMAGE_PT_uv_cursor(Panel): col.prop(sima, "cursor_location", text="Location") -class IMAGE_PT_udim_grid(Panel): +class IMAGE_PT_overlay(Panel): bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'UI' - bl_category = "View" - bl_label = "UDIM Grid" - - @classmethod - def poll(cls, context): - sima = context.space_data - - return sima.show_uvedit + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 13 def draw(self, context): - layout = self.layout - - sima = context.space_data - uvedit = sima.uv_editor - - layout.use_property_split = True - layout.use_property_decorate = False + pass - col = layout.column() - col.prop(uvedit, "tile_grid_shape", text="Grid Shape") -class IMAGE_PT_custom_grid(Panel): +class IMAGE_PT_overlay_guides(Panel): bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'UI' - bl_category = "View" - bl_label = "Custom Grid" + bl_region_type = 'HEADER' + bl_label = "Guides" + bl_parent_id = 'IMAGE_PT_overlay' @classmethod def poll(cls, context): sima = context.space_data - return sima.show_uvedit - def draw_header(self, context): - sima = context.space_data - uvedit = sima.uv_editor - self.layout.prop(uvedit, "use_custom_grid", text="") + return sima.show_uvedit def draw(self, context): layout = self.layout sima = context.space_data + overlay = sima.overlay uvedit = sima.uv_editor - layout.use_property_split = True - layout.use_property_decorate = False + layout.active = overlay.show_overlays - col = layout.column() - col.prop(uvedit, "custom_grid_subdivisions", text="Subdivisions") + row = layout.row() + row_el = row.column() + row_el.prop(overlay, "show_grid_background", text="Grid") -class IMAGE_PT_overlay(Panel): - bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'HEADER' - bl_label = "Overlays" - bl_ui_units_x = 13 + if overlay.show_grid_background: + layout.use_property_split = True + col = layout.column(align=False, heading="Fixed Subdivisions") + col.use_property_decorate = False - def draw(self, context): - pass + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(uvedit, "use_custom_grid", text="") + sub = sub.row(align=True) + sub.active = uvedit.use_custom_grid + sub.prop(uvedit, "custom_grid_subdivisions", text="") + + row = layout.row() + row.use_property_split = True + row.use_property_decorate = False + row.prop(uvedit, "tile_grid_shape", text="Tiles") class IMAGE_PT_overlay_uv_edit(Panel): @@ -1689,9 +1680,8 @@ classes = ( IMAGE_PT_scope_sample, IMAGE_PT_uv_cursor, IMAGE_PT_annotation, - IMAGE_PT_udim_grid, - IMAGE_PT_custom_grid, IMAGE_PT_overlay, + IMAGE_PT_overlay_guides, IMAGE_PT_overlay_uv_edit, IMAGE_PT_overlay_uv_edit_geometry, IMAGE_PT_overlay_texture_paint, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 6765fb3ef08..888de38dcc7 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -165,7 +165,7 @@ void BKE_pchan_minmax(const struct Object *ob, float r_max[3]); /** * Calculate the axis aligned bounds of the pose of `ob` in world-space. - + * * `r_min` and `r_max` are expanded to fit `ob->pose` so the caller must initialize them * (typically using #INIT_MINMAX). * diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 34f3b9afacd..8a2693f3f6b 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 11 +#define BLENDER_FILE_SUBVERSION 12 /* 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/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h index 2cd28c4dfa5..8b2af96a063 100644 --- a/source/blender/blenkernel/BKE_callbacks.h +++ b/source/blender/blenkernel/BKE_callbacks.h @@ -16,7 +16,7 @@ struct Main; struct PointerRNA; /** - Callbacks for One Off Actions + * Callbacks for One Off Actions * ============================= * * - `{ACTION}` use in cases where only a single callback is required, diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh index 0c576e5e48e..cd3f8dc9f58 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.hh +++ b/source/blender/blenkernel/BKE_cryptomatte.hh @@ -59,7 +59,7 @@ struct CryptomatteHash { std::string hex_encoded() const; /** - Convert a cryptomatte hash to a float. + * Convert a cryptomatte hash to a float. * * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the * cryptomatte specification. See Floating point conversion section in diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 9061bb9fb81..9fd023edcf2 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -40,7 +40,7 @@ namespace curves::nurbs { struct BasisCache { /** * For each evaluated point, the weight for all control points that influences it. - * The vector's size is the evaluated point count multiplied by the spline's order. + * The vector's size is the evaluated point count multiplied by the curve's order. */ Vector<float> weights; /** @@ -61,7 +61,7 @@ class CurvesGeometryRuntime { public: /** * Cache of offsets into the evaluated array for each curve, accounting for all previous - * evaluated points, Bezier curve vector segments, different resolutions per spline, etc. + * evaluated points, Bezier curve vector segments, different resolutions per curve, etc. */ mutable Vector<int> evaluated_offsets_cache; mutable Vector<int> bezier_evaluated_offsets; @@ -86,13 +86,13 @@ class CurvesGeometryRuntime { mutable std::mutex length_cache_mutex; mutable bool length_cache_dirty = true; - /** Direction of the spline at each evaluated point. */ - mutable Vector<float3> evaluated_tangents_cache; + /** Direction of the curve at each evaluated point. */ + mutable Vector<float3> evaluated_tangent_cache; mutable std::mutex tangent_cache_mutex; mutable bool tangent_cache_dirty = true; /** Normal direction vectors for each evaluated point. */ - mutable Vector<float3> evaluated_normals_cache; + mutable Vector<float3> evaluated_normal_cache; mutable std::mutex normal_cache_mutex; mutable bool normal_cache_dirty = true; }; @@ -158,6 +158,9 @@ class CurvesGeometry : public ::CurvesGeometry { /** Return the number of curves with each type. */ std::array<int, CURVE_TYPES_NUM> count_curve_types() const; + /** Return true if all of the curves have the provided type. */ + bool is_single_type(CurveType type) const; + Span<float3> positions() const; MutableSpan<float3> positions_for_write(); @@ -175,6 +178,13 @@ class CurvesGeometry : public ::CurvesGeometry { MutableSpan<int> resolution_for_write(); /** + * Which method to use for calculating the normals of evaluated points (#NormalMode). + * Call #tag_normals_changed after changes. + */ + VArray<int8_t> normal_mode() const; + MutableSpan<int8_t> normal_mode_for_write(); + + /** * Handle types for Bezier control points. Call #tag_topology_changed after changes. */ VArray<int8_t> handle_types_left() const; @@ -280,6 +290,8 @@ class CurvesGeometry : public ::CurvesGeometry { Span<int> bezier_evaluated_offsets_for_curve(int curve_index) const; Span<float3> evaluated_positions() const; + Span<float3> evaluated_tangents() const; + Span<float3> evaluated_normals() const; /** * Return a cache of accumulated lengths along the curve. Each item is the length of the @@ -379,6 +391,31 @@ inline float3 decode_surface_bary_coord(const float2 &v) return {v.x, v.y, 1.0f - v.x - v.y}; } +namespace poly { + +/** + * Calculate the direction at every point, defined as the normalized average of the two neighboring + * segments (and if non-cyclic, the direction of the first and last segments). This is different + * than evaluating the derivative of the basis functions for curve types like NURBS, Bezier, or + * Catmull Rom, though the results may be similar. + */ +void calculate_tangents(Span<float3> positions, bool is_cyclic, MutableSpan<float3> tangents); + +/** + * Calculate directions perpendicular to the tangent at every point by rotating an arbitrary + * starting vector by the same rotation of each tangent. If the curve is cylic, propagate a + * correction through the entire to make sure the first and last normal align. + */ +void calculate_normals_minimum(Span<float3> tangents, bool cyclic, MutableSpan<float3> normals); + +/** + * Calculate a vector perpendicular to every tangent on the X-Y plane (unless the tangent is + * vertical, in that case use the X direction). + */ +void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> normals); + +} // namespace poly + namespace bezier { /** @@ -515,7 +552,7 @@ int calculate_evaluated_size( int knots_size(int points_num, int8_t order, bool cyclic); /** - * Calculate the knots for a spline given its properties, based on built-in standards defined by + * Calculate the knots for a curve given its properties, based on built-in standards defined by * #KnotsMode. * * \note Theoretically any sorted values can be used for NURBS knots, but calculating based @@ -586,6 +623,11 @@ inline IndexRange CurvesGeometry::curves_range() const return IndexRange(this->curves_num()); } +inline bool CurvesGeometry::is_single_type(const CurveType type) const +{ + return this->count_curve_types()[type] == this->curves_num(); +} + inline IndexRange CurvesGeometry::points_for_curve(const int index) const { /* Offsets are not allocated when there are no curves. */ diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index cdee166251c..382bfd5b7db 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -43,16 +43,16 @@ typedef struct CfraElem { /* ************** F-Curve Modifiers *************** */ -/* F-Curve Modifier Type-Info (fmi): - * This struct provides function pointers for runtime, so that functions can be - * written more generally (with fewer/no special exceptions for various modifiers). +/** + * F-Curve Modifier Type-Info (fmi): + * This struct provides function pointers for runtime, so that functions can be + * written more generally (with fewer/no special exceptions for various modifiers). * - * Callers of these functions must check that they actually point to something useful, - * as some constraints don't define some of these. + * Callers of these functions must check that they actually point to something useful, + * as some constraints don't define some of these. * - * Warning: it is not too advisable to reorder order of members of this struct, - * as you'll have to edit quite a few ($FMODIFIER_NUM_TYPES) of these - * structs. + * \warning it is not too advisable to reorder order of members of this struct, + * as you'll have to edit quite a few (#FMODIFIER_NUM_TYPES) of these structs. */ typedef struct FModifierTypeInfo { /* admin/ident */ diff --git a/source/blender/blenkernel/BKE_gpencil_update_cache.h b/source/blender/blenkernel/BKE_gpencil_update_cache.h index f6ae7b53005..32d971ffdb9 100644 --- a/source/blender/blenkernel/BKE_gpencil_update_cache.h +++ b/source/blender/blenkernel/BKE_gpencil_update_cache.h @@ -31,16 +31,17 @@ typedef enum eGPUpdateCacheNodeFlag { } eGPUpdateCacheNodeFlag; /** - * Cache for what needs to be updated after bGPdata was modified. + * Cache for what needs to be updated after bGPdata was modified. * - * Every node holds information about one element that was changed: - * - the index of where that element is in the linked-list - * - the pointer to the original element in bGPdata - * Additionally, nodes also hold other nodes that are one "level" below them. - * E.g. a node that represents a change on a bGPDframe could contain a set of - * nodes that represent a change on bGPDstrokes. - * These nodes are stored in a red-black tree so that they are sorted by their - * index to make sure they can be processed in the correct order. + * Every node holds information about one element that was changed: + * - The index of where that element is in the linked-list. + * - The pointer to the original element in bGPdata. + * + * Additionally, nodes also hold other nodes that are one "level" below them. + * E.g. a node that represents a change on a bGPDframe could contain a set of + * nodes that represent a change on bGPDstrokes. + * These nodes are stored in a red-black tree so that they are sorted by their + * index to make sure they can be processed in the correct order. */ typedef struct GPencilUpdateCache { /* Mapping from index to a GPencilUpdateCache struct. */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 23f14f9be9d..c9228db9ecc 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -773,9 +773,9 @@ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree); struct bNode *nodeGetActivePaintCanvas(struct bNodeTree *ntree); /** - * @brief Does the given node supports the sub active flag. + * \brief Does the given node supports the sub active flag. * - * @param sub_active The active flag to check. NODE_ACTIVE_TEXTURE/NODE_ACTIVE_PAINT_CANVAS + * \param sub_active: The active flag to check. #NODE_ACTIVE_TEXTURE / #NODE_ACTIVE_PAINT_CANVAS. */ bool nodeSupportsActiveFlag(const struct bNode *node, int sub_active); diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 83c0f5639c4..9c4bb01c22a 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -124,7 +124,7 @@ void BKE_rigidbody_validate_sim_world(struct Scene *scene, /** * Helper function to calculate volume of rigid-body object. - + * * TODO: allow a parameter to specify method used to calculate this? */ void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 61131cff06d..aca8cdf916e 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -112,6 +112,7 @@ set(SRC intern/curve_deform.c intern/curve_eval.cc intern/curve_nurbs.cc + intern/curve_poly.cc intern/curve_to_mesh_convert.cc intern/curveprofile.cc intern/curves.cc diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 0bab3d826fd..e85524d4bcb 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -888,7 +888,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), /* This following macro should be used for all standard single-target *_get_tars functions * to save typing and reduce maintenance woes. It does not do the subtarget related operations * (Hopefully all compilers will be happy with the lines with just a space on them. Those are - * really just to help this code easier to read) + * really just to help this code easier to read) */ /* TODO: cope with getting rotation order... */ #define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \ @@ -932,7 +932,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), * to save typing and reduce maintenance woes. It does not do the subtarget related operations. * NOTE: the pointer to ct will be changed to point to the next in the list (as it gets removed) * (Hopefully all compilers will be happy with the lines with just a space on them. Those are - * really just to help this code easier to read) + * really just to help this code easier to read) */ #define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, no_copy) \ { \ diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index 9b1fd510fa8..6e09d1e8f10 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -381,6 +381,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves) curves.geometry); VArray<int> resolution = geometry.resolution(); + VArray<int8_t> normal_mode = geometry.normal_mode(); VArray_Span<float> nurbs_weights{ src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)}; @@ -436,6 +437,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves) spline->positions().fill(float3(0)); spline->tilts().fill(0.0f); spline->radii().fill(1.0f); + spline->normal_mode = static_cast<NormalMode>(normal_mode[curve_index]); curve_eval->add_spline(std::move(spline)); } @@ -448,6 +450,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves) dst_component, {"curve_type", "resolution", + "normal_mode", "nurbs_weight", "nurbs_order", "knots_mode", @@ -468,6 +471,8 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) geometry.offsets_for_write().copy_from(curve_eval.control_point_offsets()); MutableSpan<int8_t> curve_types = geometry.curve_types_for_write(); + OutputAttribute_Typed<int8_t> normal_mode = + dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE); OutputAttribute_Typed<float> nurbs_weight; OutputAttribute_Typed<int> nurbs_order; OutputAttribute_Typed<int8_t> nurbs_knots_mode; @@ -491,7 +496,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) for (const int curve_index : curve_eval.splines().index_range()) { const Spline &spline = *curve_eval.splines()[curve_index]; curve_types[curve_index] = curve_eval.splines()[curve_index]->type(); - + normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode; const IndexRange point_range = geometry.points_for_curve(curve_index); switch (spline.type()) { @@ -517,6 +522,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) } } + normal_mode.save(); nurbs_weight.save(); nurbs_order.save(); nurbs_knots_mode.save(); diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc new file mode 100644 index 00000000000..b0ed62d38dd --- /dev/null +++ b/source/blender/blenkernel/intern/curve_poly.cc @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + */ + +#include <algorithm> + +#include "BLI_math_vector.h" +#include "BLI_math_vector.hh" + +#include "BKE_curves.hh" + +namespace blender::bke::curves::poly { + +static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next) +{ + const float3 dir_prev = math::normalize(middle - prev); + const float3 dir_next = math::normalize(next - middle); + + const float3 result = math::normalize(dir_prev + dir_next); + if (UNLIKELY(math::is_zero(result))) { + return float3(0.0f, 0.0f, 1.0f); + } + return result; +} + +void calculate_tangents(const Span<float3> positions, + const bool is_cyclic, + MutableSpan<float3> tangents) +{ + BLI_assert(positions.size() == tangents.size()); + + if (positions.size() == 1) { + tangents.first() = float3(0.0f, 0.0f, 1.0f); + return; + } + + for (const int i : IndexRange(1, positions.size() - 2)) { + tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]); + } + + if (is_cyclic) { + const float3 &second_to_last = positions[positions.size() - 2]; + const float3 &last = positions.last(); + const float3 &first = positions.first(); + const float3 &second = positions[1]; + tangents.first() = direction_bisect(last, first, second); + tangents.last() = direction_bisect(second_to_last, last, first); + } + else { + tangents.first() = math::normalize(positions[1] - positions.first()); + tangents.last() = math::normalize(positions.last() - positions[positions.size() - 2]); + } +} + +static float3 rotate_direction_around_axis(const float3 &direction, + const float3 &axis, + const float angle) +{ + BLI_ASSERT_UNIT_V3(direction); + BLI_ASSERT_UNIT_V3(axis); + + const float3 axis_scaled = axis * math::dot(direction, axis); + const float3 diff = direction - axis_scaled; + const float3 cross = math::cross(axis, diff); + + return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle); +} + +void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals) +{ + BLI_assert(normals.size() == tangents.size()); + + /* Same as in `vec_to_quat`. */ + const float epsilon = 1e-4f; + for (const int i : normals.index_range()) { + const float3 &tangent = tangents[i]; + if (std::abs(tangent.x) + std::abs(tangent.y) < epsilon) { + normals[i] = {1.0f, 0.0f, 0.0f}; + } + else { + normals[i] = math::normalize(float3(tangent.y, -tangent.x, 0.0f)); + } + } +} + +/** + * Rotate the last normal in the same way the tangent has been rotated. + */ +static float3 calculate_next_normal(const float3 &last_normal, + const float3 &last_tangent, + const float3 ¤t_tangent) +{ + if (math::is_zero(last_tangent) || math::is_zero(current_tangent)) { + return last_normal; + } + const float angle = angle_normalized_v3v3(last_tangent, current_tangent); + if (angle != 0.0) { + const float3 axis = math::normalize(math::cross(last_tangent, current_tangent)); + return rotate_direction_around_axis(last_normal, axis, angle); + } + return last_normal; +} + +void calculate_normals_minimum(const Span<float3> tangents, + const bool cyclic, + MutableSpan<float3> normals) +{ + BLI_assert(normals.size() == tangents.size()); + + if (normals.is_empty()) { + return; + } + + const float epsilon = 1e-4f; + + /* Set initial normal. */ + const float3 &first_tangent = tangents.first(); + if (fabs(first_tangent.x) + fabs(first_tangent.y) < epsilon) { + normals.first() = {1.0f, 0.0f, 0.0f}; + } + else { + normals.first() = math::normalize(float3(first_tangent.y, -first_tangent.x, 0.0f)); + } + + /* Forward normal with minimum twist along the entire spline. */ + for (const int i : IndexRange(1, normals.size() - 1)) { + normals[i] = calculate_next_normal(normals[i - 1], tangents[i - 1], tangents[i]); + } + + if (!cyclic) { + return; + } + + /* Compute how much the first normal deviates from the normal that has been forwarded along the + * entire cyclic spline. */ + const float3 uncorrected_last_normal = calculate_next_normal( + normals.last(), tangents.last(), tangents.first()); + float correction_angle = angle_signed_on_axis_v3v3_v3( + normals.first(), uncorrected_last_normal, tangents.first()); + if (correction_angle > M_PI) { + correction_angle = correction_angle - 2 * M_PI; + } + + /* Gradually apply correction by rotating all normals slightly. */ + const float angle_step = correction_angle / normals.size(); + for (const int i : normals.index_range()) { + const float angle = angle_step * i; + normals[i] = rotate_direction_around_axis(normals[i], tangents[i], angle); + } +} + +} // namespace blender::bke::curves::poly diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index a76d8b08a16..5c89dfd4df5 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -25,6 +25,7 @@ static const std::string ATTR_RADIUS = "radius"; static const std::string ATTR_CURVE_TYPE = "curve_type"; static const std::string ATTR_CYCLIC = "cyclic"; static const std::string ATTR_RESOLUTION = "resolution"; +static const std::string ATTR_NORMAL_MODE = "normal_mode"; static const std::string ATTR_HANDLE_TYPE_LEFT = "handle_type_left"; static const std::string ATTR_HANDLE_TYPE_RIGHT = "handle_type_right"; static const std::string ATTR_HANDLE_POSITION_LEFT = "handle_left"; @@ -202,7 +203,8 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves, template<typename T> static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, const AttributeDomain domain, - const StringRefNull name) + const StringRefNull name, + const T default_value = T()) { const int size = domain_size(curves, domain); const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); @@ -215,7 +217,11 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, } data = (T *)CustomData_add_layer_named( &custom_data, type, CD_CALLOC, nullptr, size, name.c_str()); - return {data, size}; + MutableSpan<T> span = {data, size}; + if (size > 0 && span.first() != default_value) { + span.fill(default_value); + } + return span; } VArray<int8_t> CurvesGeometry::curve_types() const @@ -303,7 +309,7 @@ VArray<bool> CurvesGeometry::cyclic() const } MutableSpan<bool> CurvesGeometry::cyclic_for_write() { - return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC); + return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC, false); } VArray<int> CurvesGeometry::resolution() const @@ -312,7 +318,16 @@ VArray<int> CurvesGeometry::resolution() const } MutableSpan<int> CurvesGeometry::resolution_for_write() { - return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION); + return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION, 12); +} + +VArray<int8_t> CurvesGeometry::normal_mode() const +{ + return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE, 0); +} +MutableSpan<int8_t> CurvesGeometry::normal_mode_for_write() +{ + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE); } VArray<int8_t> CurvesGeometry::handle_types_left() const @@ -321,7 +336,7 @@ VArray<int8_t> CurvesGeometry::handle_types_left() const } MutableSpan<int8_t> CurvesGeometry::handle_types_left_for_write() { - return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT); + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT, 0); } VArray<int8_t> CurvesGeometry::handle_types_right() const @@ -330,7 +345,7 @@ VArray<int8_t> CurvesGeometry::handle_types_right() const } MutableSpan<int8_t> CurvesGeometry::handle_types_right_for_write() { - return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT); + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT, 0); } Span<float3> CurvesGeometry::handle_positions_left() const @@ -357,7 +372,7 @@ VArray<int8_t> CurvesGeometry::nurbs_orders() const } MutableSpan<int8_t> CurvesGeometry::nurbs_orders_for_write() { - return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER); + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER, 4); } Span<float> CurvesGeometry::nurbs_weights() const @@ -375,7 +390,7 @@ VArray<int8_t> CurvesGeometry::nurbs_knots_modes() const } MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write() { - return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE); + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0); } VArray<int> CurvesGeometry::surface_triangle_indices() const @@ -385,7 +400,7 @@ VArray<int> CurvesGeometry::surface_triangle_indices() const MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write() { - return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX); + return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1); } Span<float2> CurvesGeometry::surface_triangle_coords() const @@ -629,9 +644,117 @@ Span<float3> CurvesGeometry::evaluated_positions() const }); }); + this->runtime->position_cache_dirty = false; return this->runtime->evaluated_position_cache; } +Span<float3> CurvesGeometry::evaluated_tangents() const +{ + if (!this->runtime->tangent_cache_dirty) { + return this->runtime->evaluated_tangent_cache; + } + + /* A double checked lock. */ + std::scoped_lock lock{this->runtime->tangent_cache_mutex}; + if (!this->runtime->tangent_cache_dirty) { + return this->runtime->evaluated_tangent_cache; + } + + threading::isolate_task([&]() { + const Span<float3> evaluated_positions = this->evaluated_positions(); + const VArray<bool> cyclic = this->cyclic(); + + this->runtime->evaluated_tangent_cache.resize(this->evaluated_points_num()); + MutableSpan<float3> tangents = this->runtime->evaluated_tangent_cache; + + threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) { + for (const int curve_index : curves_range) { + const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index); + if (UNLIKELY(evaluated_points.is_empty())) { + continue; + } + curves::poly::calculate_tangents(evaluated_positions.slice(evaluated_points), + cyclic[curve_index], + tangents.slice(evaluated_points)); + } + }); + + /* Correct the first and last tangents of Bezier curves so that they align with the inner + * handles. This is a separate loop to avoid the cost when Bezier type curves are not used. */ + Vector<int64_t> bezier_indices; + const IndexMask bezier_mask = this->indices_for_curve_type(CURVE_TYPE_BEZIER, bezier_indices); + if (!bezier_mask.is_empty()) { + const Span<float3> positions = this->positions(); + const Span<float3> handles_left = this->handle_positions_left(); + const Span<float3> handles_right = this->handle_positions_right(); + + threading::parallel_for(bezier_mask.index_range(), 1024, [&](IndexRange range) { + for (const int curve_index : bezier_mask.slice(range)) { + const IndexRange points = this->points_for_curve(curve_index); + const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index); + + if (handles_right[points.first()] != positions[points.first()]) { + tangents[evaluated_points.first()] = math::normalize(handles_right[points.first()] - + positions[points.first()]); + } + if (handles_left[points.last()] != positions[points.last()]) { + tangents[evaluated_points.last()] = math::normalize(positions[points.last()] - + handles_left[points.last()]); + } + } + }); + } + }); + + this->runtime->tangent_cache_dirty = false; + return this->runtime->evaluated_tangent_cache; +} + +Span<float3> CurvesGeometry::evaluated_normals() const +{ + if (!this->runtime->normal_cache_dirty) { + return this->runtime->evaluated_normal_cache; + } + + /* A double checked lock. */ + std::scoped_lock lock{this->runtime->normal_cache_mutex}; + if (!this->runtime->normal_cache_dirty) { + return this->runtime->evaluated_normal_cache; + } + + threading::isolate_task([&]() { + const Span<float3> evaluated_tangents = this->evaluated_tangents(); + const VArray<bool> cyclic = this->cyclic(); + const VArray<int8_t> normal_mode = this->normal_mode(); + + this->runtime->evaluated_normal_cache.resize(this->evaluated_points_num()); + MutableSpan<float3> evaluated_normals = this->runtime->evaluated_normal_cache; + + threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) { + for (const int curve_index : curves_range) { + const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index); + if (UNLIKELY(evaluated_points.is_empty())) { + continue; + } + switch (normal_mode[curve_index]) { + case NORMAL_MODE_Z_UP: + curves::poly::calculate_normals_z_up(evaluated_tangents.slice(evaluated_points), + evaluated_normals.slice(evaluated_points)); + break; + case NORMAL_MODE_MINIMUM_TWIST: + curves::poly::calculate_normals_minimum(evaluated_tangents.slice(evaluated_points), + cyclic[curve_index], + evaluated_normals.slice(evaluated_points)); + break; + } + } + }); + }); + + this->runtime->normal_cache_dirty = false; + return this->runtime->evaluated_normal_cache; +} + void CurvesGeometry::interpolate_to_evaluated(const int curve_index, const GSpan src, GMutableSpan dst) const diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 27c1a2f2f33..0bcab0aae7a 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -141,81 +141,97 @@ const Curve *CurveComponent::get_curve_for_render() const namespace blender::bke { -static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals) +static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves) { - Span<int> offsets = spline.control_point_offsets(); - Span<float3> evaluated_normals = spline.evaluated_normals(); - for (const int i : IndexRange(spline.size())) { - normals[i] = evaluated_normals[offsets[i]]; - } -} + const VArray<int8_t> types = curves.curve_types(); + const VArray<int> resolutions = curves.resolution(); + const VArray<bool> curves_cyclic = curves.cyclic(); -static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals) -{ - normals.copy_from(spline.evaluated_normals()); -} + const Span<float3> positions = curves.positions(); + const VArray<int8_t> normal_modes = curves.normal_mode(); -/** - * Because NURBS control points are not necessarily on the path, the normal at the control points - * is not well defined, so create a temporary poly spline to find the normals. This requires extra - * copying currently, but may be more efficient in the future if attributes have some form of CoW. - */ -static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals) -{ - PolySpline poly_spline; - poly_spline.resize(spline.size()); - poly_spline.positions().copy_from(spline.positions()); - poly_spline.tilts().copy_from(spline.tilts()); - normals.copy_from(poly_spline.evaluated_normals()); -} + const Span<float3> evaluated_normals = curves.evaluated_normals(); -static Array<float3> curve_normal_point_domain(const CurveEval &curve) -{ - Span<SplinePtr> splines = curve.splines(); - Array<int> offsets = curve.control_point_offsets(); - const int total_size = offsets.last(); - Array<float3> normals(total_size); - - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - const Spline &spline = *splines[i]; - MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())}; - switch (splines[i]->type()) { - case CURVE_TYPE_BEZIER: - calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals); + Array<float3> results(curves.points_num()); + + threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) { + Vector<float3> nurbs_tangents; + + for (const int i_curve : range) { + const IndexRange points = curves.points_for_curve(i_curve); + const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve); + + MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points); + + switch (types[i_curve]) { + case CURVE_TYPE_CATMULL_ROM: { + const Span<float3> normals = evaluated_normals.slice(evaluated_points); + const int resolution = resolutions[i_curve]; + for (const int i : IndexRange(points.size())) { + curve_normals[i] = normals[resolution * i]; + } break; + } case CURVE_TYPE_POLY: - calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals); + curve_normals.copy_from(evaluated_normals.slice(evaluated_points)); break; - case CURVE_TYPE_NURBS: - calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals); + case CURVE_TYPE_BEZIER: { + const Span<float3> normals = evaluated_normals.slice(evaluated_points); + curve_normals.first() = normals.first(); + const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve); + for (const int i : IndexRange(points.size()).drop_front(1)) { + curve_normals[i] = normals[offsets[i - 1]]; + } break; - case CURVE_TYPE_CATMULL_ROM: - BLI_assert_unreachable(); + } + case CURVE_TYPE_NURBS: { + /* For NURBS curves there is no obvious correspondence between specific evaluated points + * and control points, so normals are determined by treating them as poly curves. */ + nurbs_tangents.clear(); + nurbs_tangents.resize(points.size()); + const bool cyclic = curves_cyclic[i_curve]; + const Span<float3> curve_positions = positions.slice(points); + bke::curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents); + switch (NormalMode(normal_modes[i_curve])) { + case NORMAL_MODE_Z_UP: + bke::curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals); + break; + case NORMAL_MODE_MINIMUM_TWIST: + bke::curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals); + break; + } break; + } } } }); - return normals; + return results; } VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) { - if (component.is_empty()) { - return nullptr; + if (!component.has_curves()) { + return {}; } - const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); + + const Curves &curves_id = *component.get_for_read(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + + const VArray<int8_t> types = curves.curve_types(); + if (curves.is_single_type(CURVE_TYPE_POLY)) { + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain); + } + + Array<float3> normals = curve_normal_point_domain(curves); if (domain == ATTR_DOMAIN_POINT) { - Array<float3> normals = curve_normal_point_domain(*curve); return VArray<float3>::ForContainer(std::move(normals)); } if (domain == ATTR_DOMAIN_CURVE) { - Array<float3> point_normals = curve_normal_point_domain(*curve); - VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); return component.attribute_try_adapt_domain<float3>( - std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; @@ -456,6 +472,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() make_array_write_attribute<int>, tag_component_topology_changed); + static BuiltinCustomDataLayerProvider normal_mode("normal_mode", + ATTR_DOMAIN_CURVE, + CD_PROP_INT8, + CD_PROP_INT8, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<int8_t>, + make_array_write_attribute<int8_t>, + tag_component_normals_changed); + static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode", ATTR_DOMAIN_CURVE, CD_PROP_INT8, @@ -490,7 +518,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() curve_access, make_array_read_attribute<int>, make_array_write_attribute<int>, - tag_component_positions_changed); + tag_component_topology_changed); static BuiltinCustomDataLayerProvider cyclic("cyclic", ATTR_DOMAIN_CURVE, @@ -515,6 +543,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() &handle_left, &handle_type_right, &handle_type_left, + &normal_mode, &nurbs_order, &nurbs_weight, &curve_type, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 5fcb53acfcc..a2338eb9b39 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -157,6 +157,7 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f id_us_plus(dst_id->override_library->reference); dst_id->override_library->hierarchy_root = src_id->override_library->hierarchy_root; + dst_id->override_library->flag = src_id->override_library->flag; if (do_full_copy) { BLI_duplicatelist(&dst_id->override_library->properties, diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c index 8a540f48c23..5e9d8e8c4d0 100644 --- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c +++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c @@ -9,6 +9,11 @@ #include "MEM_guardedalloc.h" +#include "BLI_linklist.h" + +/* Required for proxy to liboverrides conversion code. */ +#define DNA_DEPRECATED_ALLOW + #include "DNA_ID.h" #include "DNA_collection_types.h" #include "DNA_object_types.h" @@ -107,23 +112,29 @@ static void lib_override_library_proxy_convert_do(Main *bmain, void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LinkNodePair proxy_objects = {NULL}; + FOREACH_SCENE_OBJECT_BEGIN (scene, object) { - if (object->proxy_group == NULL) { - continue; + if (object->proxy_group != NULL) { + BLI_linklist_append(&proxy_objects, object); } - - lib_override_library_proxy_convert_do(bmain, scene, object, reports); } FOREACH_SCENE_OBJECT_END; FOREACH_SCENE_OBJECT_BEGIN (scene, object) { - if (object->proxy == NULL) { - continue; + if (object->proxy != NULL && object->proxy_group == NULL) { + BLI_linklist_append(&proxy_objects, object); } - - lib_override_library_proxy_convert_do(bmain, scene, object, reports); } FOREACH_SCENE_OBJECT_END; + + for (LinkNode *proxy_object_iter = proxy_objects.list; proxy_object_iter != NULL; + proxy_object_iter = proxy_object_iter->next) { + Object *proxy_object = proxy_object_iter->link; + lib_override_library_proxy_convert_do(bmain, scene, proxy_object, reports); + } + + BLI_linklist_free(proxy_objects.list, NULL); } LISTBASE_FOREACH (Object *, object, &bmain->objects) { diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index f783121d02c..84aabbc7a9b 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -134,6 +134,14 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v, return v < min ? min : (v > max ? max : v); } +static ScanFillVert *scanfill_vert_add_v2_with_depth(ScanFillContext *sf_ctx, + const float co_xy[2], + const float co_z) +{ + const float co[3] = {co_xy[0], co_xy[1], co_z}; + return BLI_scanfill_vert_add(sf_ctx, co); +} + /* --------------------------------------------------------------------- */ /* local structs for mask rasterizing */ /* --------------------------------------------------------------------- */ @@ -646,9 +654,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, ScanFillVert *sf_vert_prev; unsigned int j; - float co[3]; - co[2] = 0.0f; - sf_ctx.poly_nr++; if (do_aspect_correct) { @@ -704,8 +709,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, spline, diff_feather_points, tot_diff_feather_points); } - copy_v2_v2(co, diff_points[0]); - sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert_prev = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[0], 0.0f); sf_vert_prev->tmp.u = sf_vert_tot; /* Absolute index of feather vert. */ @@ -713,10 +717,8 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, sf_vert_tot++; - /* TODO: an alternate functions so we can avoid double vector copy! */ for (j = 1; j < tot_diff_point; j++) { - copy_v2_v2(co, diff_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ sf_vert_tot++; @@ -741,16 +743,12 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, } if (diff_feather_points) { - float co_feather[3]; - co_feather[2] = 1.0f; - BLI_assert(tot_diff_feather_points == tot_diff_point); /* NOTE: only added for convenience, we don't in fact use these to scan-fill, * only to create feather faces after scan-fill. */ for (j = 0; j < tot_diff_feather_points; j++) { - copy_v2_v2(co_feather, diff_feather_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f); sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; } @@ -762,15 +760,11 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, /* unfilled spline */ if (diff_feather_points) { - float co_diff[2]; - - float co_feather[3]; - co_feather[2] = 1.0f; - if (spline->flag & MASK_SPLINE_NOINTERSECT) { diff_feather_points_flip = MEM_mallocN(sizeof(float[2]) * tot_diff_feather_points, "diff_feather_points_flip"); + float co_diff[2]; for (j = 0; j < tot_diff_point; j++) { sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]); add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff); @@ -792,29 +786,29 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, for (j = 0; j < tot_diff_point; j++) { /* center vert */ - copy_v2_v2(co, diff_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; /* feather vert A */ - copy_v2_v2(co_feather, diff_feather_points[j]); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; /* feather vert B */ if (diff_feather_points_flip) { - copy_v2_v2(co_feather, diff_feather_points_flip[j]); + sf_vert = scanfill_vert_add_v2_with_depth( + &sf_ctx, diff_feather_points_flip[j], 1.0f); } else { - sub_v2_v2v2(co_diff, co, co_feather); - add_v2_v2v2(co_feather, co, co_diff); + float co_diff[2]; + sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]); + add_v2_v2v2(co_diff, diff_points[j], co_diff); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_diff, 1.0f); } - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; @@ -857,9 +851,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, for (k = 1; k < vertex_total_cap; k++) { const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; + float co_feather[2]; rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; @@ -877,9 +872,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, for (k = 1; k < vertex_total_cap; k++) { const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI; + float co_feather[2]; rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy); - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); + sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f); sf_vert->tmp.u = sf_vert_tot; sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 4e6191cca6f..0430269b75a 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -322,6 +322,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int SEQ_DUPE_ALL, flag_subdata); BLI_duplicatelist(&scene_dst->ed->channels, &scene_src->ed->channels); + scene_dst->ed->displayed_channels = &scene_dst->ed->channels; } if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc index aa79199d668..e84ec5b3890 100644 --- a/source/blender/blenkernel/intern/type_conversions.cc +++ b/source/blender/blenkernel/intern/type_conversions.cc @@ -21,7 +21,7 @@ static void add_implicit_conversion(DataTypeConversions &conversions) static fn::CustomMF_SI_SO<From, To> multi_function{ conversion_name.c_str(), /* Use lambda instead of passing #ConversionF directly, because otherwise the compiler won't - inline the function. */ + * inline the function. */ [](const From &a) { return ConversionF(a); }}; static auto convert_single_to_initialized = [](const void *src, void *dst) { *(To *)dst = ConversionF(*(const From *)src); diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h index 2d8428e164f..53c2ff1c345 100644 --- a/source/blender/blenlib/BLI_delaunay_2d.h +++ b/source/blender/blenlib/BLI_delaunay_2d.h @@ -5,8 +5,8 @@ /** \file * \ingroup bli * - * This header file contains both a C interface and a C++ interface - * to the 2D Constrained Delaunay Triangulation library routine. + * This header file contains both a C interface and a C++ interface + * to the 2D Constrained Delaunay Triangulation library routine. */ #ifdef __cplusplus diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 04b40904187..3ce2b90e729 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -270,7 +270,7 @@ struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESUL void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size); /** * Return the text file data with: - + * * - Newlines replaced with '\0'. * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'. * diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh index ba1d9b293c7..22ea83760aa 100644 --- a/source/blender/blenlib/BLI_mesh_intersect.hh +++ b/source/blender/blenlib/BLI_mesh_intersect.hh @@ -5,8 +5,8 @@ /** \file * \ingroup bli * - * Mesh intersection library functions. - * Uses exact arithmetic, so need GMP. + * Mesh intersection library functions. + * Uses exact arithmetic, so need GMP. */ #ifdef WITH_GMP diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 7d0884f83dc..45abac33795 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -255,7 +255,7 @@ size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t * * \param str: Typically this is the first character in a quoted string. * Where the character before `*str` would be `"`. - + * * \return The pointer to the first un-escaped quote. */ const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(); diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc index 804ba5c3c80..ece22bcf82e 100644 --- a/source/blender/blenlib/intern/delaunay_2d.cc +++ b/source/blender/blenlib/intern/delaunay_2d.cc @@ -2807,7 +2807,7 @@ blender::meshintersect::CDT_result<mpq_class> delaunay_2d_calc(const CDT_input<m /* C interface. */ /** - This function uses the double version of #CDT::delaunay_calc. + * This function uses the double version of #CDT::delaunay_calc. * Almost all of the work here is to convert between C++ #Arrays<Vector<int>> * and a C version that linearizes all the elements and uses a "start" * and "len" array to say where the individual vectors start and how diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc index 885d2c13b49..132d5dfda65 100644 --- a/source/blender/blenlib/intern/math_boolean.cc +++ b/source/blender/blenlib/intern/math_boolean.cc @@ -1857,23 +1857,23 @@ double incircle(const double *pa, const double *pb, const double *pc, const doub } /** - * inspherefast() Approximate 3D insphere test. Non-robust. - * insphere() Adaptive exact 3D insphere test. Robust. + * inspherefast() Approximate 3D insphere test. Non-robust. + * insphere() Adaptive exact 3D insphere test. Robust. * - * Return a positive value if the point pe lies inside the - * sphere passing through pa, pb, pc, and pd; a negative value - * if it lies outside; and zero if the five points are - * co-spherical. The points pa, pb, pc, and pd must be ordered - * so that they have a positive orientation (as defined by - * orient3d()), or the sign of the result will be reversed. + * Return a positive value if the point pe lies inside the + * sphere passing through pa, pb, pc, and pd; a negative value + * if it lies outside; and zero if the five points are + * co-spherical. The points pa, pb, pc, and pd must be ordered + * so that they have a positive orientation (as defined by + * orient3d()), or the sign of the result will be reversed. * - * The second uses exact arithmetic to ensure a correct answer. The - * result returned is the determinant of a matrix. In insphere() only, - * this determinant is computed adaptively, in the sense that exact - * arithmetic is used only to the degree it is needed to ensure that the - * returned value has the correct sign. Hence, insphere() is usually quite - * fast, but will run more slowly when the input points are co-spherical or - * nearly so. + * The second uses exact arithmetic to ensure a correct answer. The + * result returned is the determinant of a matrix. In insphere() only, + * this determinant is computed adaptively, in the sense that exact + * arithmetic is used only to the degree it is needed to ensure that the + * returned value has the correct sign. Hence, insphere() is usually quite + * fast, but will run more slowly when the input points are co-spherical or + * nearly so. */ double inspherefast( diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index a00bbaec8dd..95851c0e9ff 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -2354,6 +2354,21 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 301, 7) || + (bmain->versionfile == 302 && !MAIN_VERSION_ATLEAST(bmain, 302, 4))) { + /* Duplicate value for two flags that mistakenly had the same numeric value. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_WeightVGProximity) { + WeightVGProximityModifierData *wpmd = (WeightVGProximityModifierData *)md; + if (wpmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK) { + wpmd->proximity_flags |= MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE; + } + } + } + } + } + if (!MAIN_VERSION_ATLEAST(bmain, 302, 2)) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { if (scene->ed != NULL) { @@ -2552,9 +2567,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } - } - if (!MAIN_VERSION_ATLEAST(bmain, 302, 10)) { /* While vertex-colors were experimental the smear tool became corrupt due * to bugs in the wm_toolsystem API (auto-creation of sculpt brushes * was broken). Go through and reset all smear brushes. */ @@ -2622,17 +2635,18 @@ 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, 302, 12)) { + /* UV/Image show background grid option. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) { + if (space->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)space; + sima->overlay.flag |= SI_OVERLAY_SHOW_GRID_BACKGROUND; + } + } + } + } /* Add node storage for the merge by distance node. */ FOREACH_NODETREE_BEGIN (bmain, ntree, id) { @@ -2651,4 +2665,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } FOREACH_NODETREE_END; } + + /** + * 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/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index c38393e9284..5597d496890 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -988,7 +988,7 @@ void discard_edit_mode_pointers(ID *id_cow) } // namespace /** - Free content of the CoW data-block. + * Free content of the CoW data-block. * Notes: * - Does not recurse into nested ID data-blocks. * - Does not free data-block itself. diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 58676caa6f9..ee70cebcfd2 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -27,25 +27,12 @@ static void eevee_motion_blur_mesh_data_free(void *val) { - EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val; - EEVEE_HairMotionData *hair_mb = (EEVEE_HairMotionData *)val; - switch (geom_mb->type) { - case EEVEE_MOTION_DATA_HAIR: - for (int j = 0; j < hair_mb->psys_len; j++) { - for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) { - GPU_VERTBUF_DISCARD_SAFE(hair_mb->psys[j].hair_pos[i]); - } - for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) { - DRW_TEXTURE_FREE_SAFE(hair_mb->psys[j].hair_pos_tx[i]); - } - } - break; - - case EEVEE_MOTION_DATA_MESH: - for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { - GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]); - } - break; + EEVEE_ObjectMotionData *mb_data = (EEVEE_ObjectMotionData *)val; + if (mb_data->hair_data != NULL) { + MEM_freeN(mb_data->hair_data); + } + if (mb_data->geometry_data != NULL) { + MEM_freeN(mb_data->geometry_data); } MEM_freeN(val); } @@ -84,39 +71,59 @@ static bool eevee_object_key_cmp(const void *a, const void *b) return false; } +void EEVEE_motion_hair_step_free(EEVEE_HairMotionStepData *step_data) +{ + GPU_vertbuf_discard(step_data->hair_pos); + DRW_texture_free(step_data->hair_pos_tx); + MEM_freeN(step_data); +} + void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb) { if (mb->object == NULL) { mb->object = BLI_ghash_new(eevee_object_key_hash, eevee_object_key_cmp, "EEVEE Object Motion"); } - if (mb->geom == NULL) { - mb->geom = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE Mesh Motion"); + for (int i = 0; i < 2; i++) { + if (mb->position_vbo_cache[i] == NULL) { + mb->position_vbo_cache[i] = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE duplicate vbo cache"); + } + if (mb->hair_motion_step_cache[i] == NULL) { + mb->hair_motion_step_cache[i] = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE hair motion step cache"); + } } } void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb) { if (mb->object) { - BLI_ghash_free(mb->object, MEM_freeN, MEM_freeN); + BLI_ghash_free(mb->object, MEM_freeN, eevee_motion_blur_mesh_data_free); mb->object = NULL; } - if (mb->geom) { - BLI_ghash_free(mb->geom, NULL, eevee_motion_blur_mesh_data_free); - mb->geom = NULL; + for (int i = 0; i < 2; i++) { + if (mb->position_vbo_cache[i]) { + BLI_ghash_free(mb->position_vbo_cache[i], NULL, (GHashValFreeFP)GPU_vertbuf_discard); + mb->position_vbo_cache[i] = NULL; + } + if (mb->hair_motion_step_cache[i]) { + BLI_ghash_free( + mb->hair_motion_step_cache[i], NULL, (GHashValFreeFP)EEVEE_motion_hair_step_free); + mb->hair_motion_step_cache[i] = NULL; + } } } -EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, - Object *ob, - bool hair) +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob) { if (mb->object == NULL) { return NULL; } EEVEE_ObjectKey key, *key_p; - /* Small hack to avoid another comparison. */ - key.ob = (Object *)((char *)ob + hair); + /* Assumes that all instances have the same object pointer. This is currently the case because + * instance objects are temporary objects on the stack. */ + key.ob = ob; DupliObject *dup = DRW_object_get_dupli(ob); if (dup) { key.parent = DRW_object_get_dupli_parent(ob); @@ -139,53 +146,28 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData * return ob_step; } -static void *motion_blur_deform_data_get(EEVEE_MotionBlurData *mb, Object *ob, bool hair) +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_ObjectMotionData *mb_data) { - if (mb->geom == NULL) { - return NULL; + if (mb_data->geometry_data == NULL) { + EEVEE_GeometryMotionData *geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); + geom_step->type = EEVEE_MOTION_DATA_MESH; + mb_data->geometry_data = geom_step; } - DupliObject *dup = DRW_object_get_dupli(ob); - void *key; - if (dup) { - key = dup->ob; - } - else { - key = ob; - } - /* Only use data for object that have no modifiers. */ - if (!BKE_object_is_modified(DRW_context_state_get()->scene, ob)) { - key = ob->data; - } - key = (char *)key + (int)hair; - EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key); - if (geom_step == NULL) { - if (hair) { - EEVEE_HairMotionData *hair_step; - /* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */ - int psys_len = (ob->type != OB_CURVES) ? BLI_listbase_count(&ob->modifiers) : 1; - hair_step = MEM_callocN(sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, - __func__); - hair_step->psys_len = psys_len; - geom_step = (EEVEE_GeometryMotionData *)hair_step; - geom_step->type = EEVEE_MOTION_DATA_HAIR; - } - else { - geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); - geom_step->type = EEVEE_MOTION_DATA_MESH; - } - BLI_ghash_insert(mb->geom, key, geom_step); - } - return geom_step; + return mb_data->geometry_data; } -EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, Object *ob) +EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb_data, Object *ob) { - return motion_blur_deform_data_get(mb, ob, false); -} - -EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, Object *ob) -{ - return motion_blur_deform_data_get(mb, ob, true); + if (mb_data->hair_data == NULL) { + /* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */ + int psys_len = (ob->type != OB_CURVES) ? BLI_listbase_count(&ob->modifiers) : 1; + EEVEE_HairMotionData *hair_step = MEM_callocN( + sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, __func__); + hair_step->psys_len = psys_len; + hair_step->type = EEVEE_MOTION_DATA_HAIR; + mb_data->hair_data = hair_step; + } + return mb_data->hair_data; } /* View Layer data. */ diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index ccedff4d1e3..a1cd110e1d8 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -479,6 +479,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD method.update_screen_space_bounds(region); method.update_screen_uv_bounds(); + /* Check for changes in the image user compared to the last time. */ + instance_data->update_image_usage(iuser); + /* Step: Update the GPU textures based on the changes in the image. */ instance_data->update_gpu_texture_allocations(); update_textures(*instance_data, image, iuser); diff --git a/source/blender/draw/engines/image/image_space.hh b/source/blender/draw/engines/image/image_space.hh index 7a11d14b567..03973d892df 100644 --- a/source/blender/draw/engines/image/image_space.hh +++ b/source/blender/draw/engines/image/image_space.hh @@ -10,10 +10,10 @@ struct ShaderParameters; /** - * Space accessor. + * Space accessor. * - * Image engine is used to draw the images inside multiple spaces \see SpaceLink. - * The AbstractSpaceAccessor is an interface to communicate with a space. + * Image engine is used to draw the images inside multiple spaces \see SpaceLink. + * The #AbstractSpaceAccessor is an interface to communicate with a space. */ class AbstractSpaceAccessor { public: diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c index 20403f156a1..ed6db459696 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.c +++ b/source/blender/draw/engines/overlay/overlay_grid.c @@ -49,20 +49,29 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) if (pd->space_type == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; View2D *v2d = &draw_ctx->region->v2d; - if (sima->mode == SI_MODE_UV || !ED_space_image_has_buffer(sima)) { - shd->grid_flag = GRID_BACK | PLANE_IMAGE | SHOW_GRID; - } - else { - shd->grid_flag = 0; + + /* Only UV Edit mode has the various Overlay options for now. */ + const bool is_uv_edit = sima->mode == SI_MODE_UV; + + const bool background_enabled = is_uv_edit ? (!pd->hide_overlays && + (sima->overlay.flag & + SI_OVERLAY_SHOW_GRID_BACKGROUND) != 0) : + true; + if (background_enabled) { + shd->grid_flag = GRID_BACK | PLANE_IMAGE; } - if (sima->flag & SI_CUSTOM_GRID) { - shd->grid_flag |= CUSTOM_GRID; + const bool draw_grid = is_uv_edit || !ED_space_image_has_buffer(sima); + if (background_enabled && draw_grid) { + shd->grid_flag |= SHOW_GRID; + if (is_uv_edit && (sima->flag & SI_CUSTOM_GRID) != 0) { + shd->grid_flag |= CUSTOM_GRID; + } } shd->grid_distance = 1.0f; copy_v3_fl3(shd->grid_size, 1.0f, 1.0f, 1.0f); - if (sima->mode == SI_MODE_UV) { + if (is_uv_edit) { shd->grid_size[0] = (float)sima->tile_grid_shape[0]; shd->grid_size[1] = (float)sima->tile_grid_shape[1]; } diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh index d3766da23cf..e2a54788c72 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh @@ -92,7 +92,7 @@ GPU_SHADER_CREATE_INFO(workbench_material) GPU_SHADER_CREATE_INFO(workbench_transparent_accum) /* Note: Blending will be skipped on objectId because output is a - non-normalized integer buffer. */ + * non-normalized integer buffer. */ .fragment_out(0, Type::VEC4, "transparentAccum") .fragment_out(1, Type::VEC4, "revealageAccum") .fragment_out(2, Type::UINT, "objectId") diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index 59aa4bc7683..2653035a39f 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -518,6 +518,11 @@ static void draw_patch_map_free(DRWPatchMap *gpu_patch_map) /** \name DRWSubdivCache * \{ */ +static bool draw_subdiv_cache_need_polygon_data(const DRWSubdivCache *cache) +{ + return cache->subdiv && cache->subdiv->evaluator && cache->num_subdiv_loops != 0; +} + static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache) { GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset); @@ -551,6 +556,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache) cache->num_subdiv_triangles = 0; cache->num_coarse_poly = 0; cache->num_subdiv_quads = 0; + cache->may_have_loose_geom = false; draw_subdiv_free_edit_mode_cache(cache); draw_subdiv_cache_free_material_data(cache); draw_patch_map_free(&cache->gpu_patch_map); @@ -558,6 +564,11 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache) GPU_uniformbuf_free(cache->ubo); cache->ubo = nullptr; } + MEM_SAFE_FREE(cache->loose_geom.edges); + MEM_SAFE_FREE(cache->loose_geom.verts); + cache->loose_geom.edge_len = 0; + cache->loose_geom.vert_len = 0; + cache->loose_geom.loop_len = 0; } /* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of @@ -734,19 +745,25 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con const int num_polygons, const int *subdiv_polygon_offset) { - if (num_loops == 0) { + /* num_loops does not take into account meshes with only loose geometry, which might be meshes + * used as custom bone shapes, so let's check the num_vertices also. */ + if (num_vertices == 0 && num_loops == 0) { return false; } DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); DRWSubdivCache *cache = ctx->cache; - /* Set topology information. */ - cache->num_subdiv_edges = (uint)num_edges; - cache->num_subdiv_loops = (uint)num_loops; - cache->num_subdiv_verts = (uint)num_vertices; - cache->num_subdiv_quads = (uint)num_polygons; - cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset)); + /* Set topology information only if we have loops. */ + if (num_loops != 0) { + cache->num_subdiv_edges = (uint)num_edges; + cache->num_subdiv_loops = (uint)num_loops; + cache->num_subdiv_verts = (uint)num_vertices; + cache->num_subdiv_quads = (uint)num_polygons; + cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset)); + } + + cache->may_have_loose_geom = num_vertices != 0 || num_edges != 0; /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after * it was sent to the device, since we may use the data while building other buffers on the CPU @@ -789,16 +806,20 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con ctx->e_origindex = static_cast<int *>( CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); - ctx->vert_origindex_map = static_cast<int *>( - MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map")); - for (int i = 0; i < num_vertices; i++) { - ctx->vert_origindex_map[i] = -1; + if (cache->num_subdiv_verts) { + ctx->vert_origindex_map = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map")); + for (int i = 0; i < num_vertices; i++) { + ctx->vert_origindex_map[i] = -1; + } } - ctx->edge_origindex_map = static_cast<int *>( - MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map")); - for (int i = 0; i < num_edges; i++) { - ctx->edge_origindex_map[i] = -1; + if (cache->num_subdiv_edges) { + ctx->edge_origindex_map = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map")); + for (int i = 0; i < num_edges; i++) { + ctx->edge_origindex_map[i] = -1; + } } return true; @@ -842,6 +863,10 @@ static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context, { DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); + if (!ctx->edge_origindex_map) { + return; + } + int coarse_index = coarse_edge_index; if (coarse_index != -1) { @@ -991,7 +1016,8 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, cache_building_context.cache = cache; do_subdiv_traversal(&cache_building_context, subdiv); - if (cache->num_subdiv_loops == 0) { + if (cache->num_subdiv_loops == 0 && cache->num_subdiv_verts == 0 && + !cache->may_have_loose_geom) { /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further. * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly. */ @@ -999,44 +1025,47 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache, return false; } - /* Build buffers for the PatchMap. */ - draw_patch_map_build(&cache->gpu_patch_map, subdiv); + /* Only build polygon related data if we have polygons. */ + if (cache->num_subdiv_loops != 0) { + /* Build buffers for the PatchMap. */ + draw_patch_map_build(&cache->gpu_patch_map, subdiv); + + cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + + /* Build patch coordinates for all the face dots. */ + cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), + mesh_eval->totpoly); + CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *) + GPU_vertbuf_get_data(cache->fdots_patch_coords); + for (int i = 0; i < mesh_eval->totpoly; i++) { + const int ptex_face_index = cache->face_ptex_offset[i]; + if (mesh_eval->mpoly[i].totloop == 4) { + /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */ + blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f); + } + else { + /* For N-gons, since they are split into quads from the center, and since the center is + * chosen to be the top right corner of each quad, the center coordinate of the coarse face + * is any one of those top right corners with `u = v = 1.0`. */ + blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f); + } + } - cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer( + cache->subdiv_polygon_offset, mesh_eval->totpoly); - /* Build patch coordinates for all the face dots. */ - cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), - mesh_eval->totpoly); - CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data( - cache->fdots_patch_coords); - for (int i = 0; i < mesh_eval->totpoly; i++) { - const int ptex_face_index = cache->face_ptex_offset[i]; - if (mesh_eval->mpoly[i].totloop == 4) { - /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */ - blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f); - } - else { - /* For N-gons, since they are split into quads from the center, and since the center is - * chosen to be the top right corner of each quad, the center coordinate of the coarse face - * is any one of those top right corners with `u = v = 1.0`. */ - blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f); - } + cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset, + mesh_eval->totpoly + 1); + + build_vertex_face_adjacency_maps(cache); } cache->resolution = to_mesh_settings.resolution; - - cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer( - cache->subdiv_polygon_offset, mesh_eval->totpoly); - - cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset, - mesh_eval->totpoly + 1); cache->num_coarse_poly = mesh_eval->totpoly; - build_vertex_face_adjacency_maps(cache); - /* Cleanup. */ - MEM_freeN(cache_building_context.vert_origindex_map); - MEM_freeN(cache_building_context.edge_origindex_map); + MEM_SAFE_FREE(cache_building_context.vert_origindex_map); + MEM_SAFE_FREE(cache_building_context.edge_origindex_map); return true; } @@ -1192,6 +1221,11 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache, void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor) { + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + Subdiv *subdiv = cache->subdiv; OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; @@ -1251,6 +1285,11 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, const int face_varying_channel, const int dst_offset) { + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + Subdiv *subdiv = cache->subdiv; OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; @@ -1484,6 +1523,11 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, GPUIndexBuf *subdiv_tris, const int material_count) { + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + const bool do_single_material = material_count <= 1; const char *defines = "#define SUBDIV_POLYGON_OFFSET\n"; @@ -1527,6 +1571,11 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache, GPUVertBuf *fdots_nor, GPUIndexBuf *fdots_indices) { + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + Subdiv *subdiv = cache->subdiv; OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; @@ -1651,6 +1700,11 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, GPUVertBuf *pos_nor, GPUVertBuf *lnor) { + if (!draw_subdiv_cache_need_polygon_data(cache)) { + /* Happens on meshes with only loose geometry. */ + return; + } + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n"); GPU_shader_bind(shader); @@ -1839,9 +1893,9 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, const float obmat[4][4], const bool do_final, const bool do_uvedit, - const bool UNUSED(use_subsurf_fdots), + const bool /*use_subsurf_fdots*/, const ToolSettings *ts, - const bool UNUSED(use_hide), + const bool /*use_hide*/, OpenSubdiv_EvaluatorCache *evaluator_cache) { SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob); @@ -1872,7 +1926,15 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, if (!BKE_subdiv_eval_begin_from_mesh( subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) { - return false; + /* This could happen in two situations: + * - OpenSubdiv is disabled. + * - Something totally bad happened, and OpenSubdiv rejected our + * topology. + * In either way, we can't safely continue. However, we still have to handle potential loose + * geometry, which is done separately. */ + if (mesh_eval->totpoly) { + return false; + } } DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); @@ -1909,6 +1971,104 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, return true; } +void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache) +{ + const int coarse_loose_vert_len = cache->loose_geom.vert_len; + const int coarse_loose_edge_len = cache->loose_geom.edge_len; + + if (coarse_loose_vert_len == 0 && coarse_loose_edge_len == 0) { + /* Nothing to do. */ + return; + } + + if (subdiv_cache->loose_geom.edges || subdiv_cache->loose_geom.verts) { + /* Already processed. */ + return; + } + + const Mesh *coarse_mesh = subdiv_cache->mesh; + const bool is_simple = subdiv_cache->subdiv->settings.is_simple; + const int resolution = subdiv_cache->resolution; + const int resolution_1 = resolution - 1; + const float inv_resolution_1 = 1.0f / (float)resolution_1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + + const int num_subdivided_edge = coarse_loose_edge_len * + (num_subdiv_vertices_per_coarse_edge + 1); + + /* Each edge will store data for its 2 verts, that way we can keep the overall logic simple, here + * and in the buffer extractors. Although it duplicates memory (and work), the buffers also store + * duplicate values. */ + const int num_subdivided_verts = num_subdivided_edge * 2; + + DRWSubdivLooseEdge *loose_subd_edges = static_cast<DRWSubdivLooseEdge *>( + MEM_callocN(sizeof(DRWSubdivLooseEdge) * num_subdivided_edge, "DRWSubdivLooseEdge")); + + DRWSubdivLooseVertex *loose_subd_verts = static_cast<DRWSubdivLooseVertex *>( + MEM_callocN(sizeof(DRWSubdivLooseVertex) * (num_subdivided_verts + coarse_loose_vert_len), + "DRWSubdivLooseEdge")); + + int subd_edge_offset = 0; + int subd_vert_offset = 0; + + /* Subdivide each loose coarse edge. */ + for (int i = 0; i < coarse_loose_edge_len; i++) { + const int coarse_edge_index = cache->loose_geom.edges[i]; + const MEdge *coarse_edge = &coarse_mesh->medge[cache->loose_geom.edges[i]]; + + /* Perform interpolation of each vertex. */ + for (int i = 0; i < resolution - 1; i++, subd_edge_offset++) { + DRWSubdivLooseEdge &subd_edge = loose_subd_edges[subd_edge_offset]; + subd_edge.coarse_edge_index = coarse_edge_index; + + /* First vert. */ + DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset]; + subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge->v1 : -1u; + const float u1 = i * inv_resolution_1; + BKE_subdiv_mesh_interpolate_position_on_edge( + coarse_mesh, coarse_edge, is_simple, u1, subd_v1.co); + + subd_edge.loose_subdiv_v1_index = subd_vert_offset++; + + /* Second vert. */ + DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset]; + subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge->v2 : -1u; + const float u2 = (i + 1) * inv_resolution_1; + BKE_subdiv_mesh_interpolate_position_on_edge( + coarse_mesh, coarse_edge, is_simple, u2, subd_v2.co); + + subd_edge.loose_subdiv_v2_index = subd_vert_offset++; + } + } + + /* Copy the remaining loose_verts. */ + for (int i = 0; i < coarse_loose_vert_len; i++) { + const int coarse_vertex_index = cache->loose_geom.verts[i]; + const MVert &coarse_vertex = coarse_mesh->mvert[coarse_vertex_index]; + + DRWSubdivLooseVertex &subd_v = loose_subd_verts[subd_vert_offset++]; + subd_v.coarse_vertex_index = cache->loose_geom.verts[i]; + copy_v3_v3(subd_v.co, coarse_vertex.co); + } + + subdiv_cache->loose_geom.edges = loose_subd_edges; + subdiv_cache->loose_geom.verts = loose_subd_verts; + subdiv_cache->loose_geom.edge_len = num_subdivided_edge; + subdiv_cache->loose_geom.vert_len = coarse_loose_vert_len; + subdiv_cache->loose_geom.loop_len = num_subdivided_edge * 2 + coarse_loose_vert_len; +} + +blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache) +{ + return {cache->loose_geom.edges, static_cast<int64_t>(cache->loose_geom.edge_len)}; +} + +blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache) +{ + return {cache->loose_geom.verts + cache->loose_geom.edge_len * 2, + static_cast<int64_t>(cache->loose_geom.vert_len)}; +} + static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; void DRW_create_subdivision(const Scene *scene, diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index cf04cdba859..0efa32ec63a 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -8,20 +8,20 @@ * ==================== * * - Push & Relax, Breakdowner - + * * These tools provide the animator with various capabilities * for interactively controlling the spacing of poses, but also * for 'pushing' and/or 'relaxing' extremes as they see fit. * * - Propagate - + * * This tool copies elements of the selected pose to successive * keyframes, allowing the animator to go back and modify the poses * for some "static" pose controls, without having to repeatedly * doing a "next paste" dance. * * - Pose Sculpting (TODO) - + * * This is yet to be implemented, but the idea here is to use * sculpting techniques to make it easier to pose rigs by allowing * rigs to be manipulated using a familiar paint-based interface. diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 4941e11a7b3..55167c1ed2d 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -41,7 +41,7 @@ namespace blender::ed::asset { /* -------------------------------------------------------------------- */ /** \name Asset list API * - * Internally re-uses #FileList from the File Browser. It does all the heavy lifting already. + * Internally re-uses #FileList from the File Browser. It does all the heavy lifting already. * \{ */ /** diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 9df8c099819..3f06dbfdbb3 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1239,7 +1239,7 @@ static bool contract_shape(ImBuf *ibuf) const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const int max_size = (ibuf->x * ibuf->y) - 1; - /* Detect if pixel is near of no green pixels and mark green to be cleared. */ + /* Detect if pixel is near of no green pixels and mark green pixel to be cleared. */ for (int row = 0; row < ibuf->y; row++) { if (!is_row_filled(ibuf, row)) { continue; diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 7de579993c1..3cdf364e4b2 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1627,7 +1627,7 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, */ gpencil_brush_grab_stroke_init(gso, gps_active); changed |= gpencil_sculpt_brush_do_stroke( - gso, gps_active, diff_mat, gpencil_brush_grab_store_points); + gso, gps_active, bound_mat, gpencil_brush_grab_store_points); } else { /* Apply effect to the stored points */ diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index 6b015895b60..cd28fbe9687 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -12,6 +12,7 @@ extern "C" { #endif +struct bToolRef; struct PaintModeSettings; struct ImBuf; struct Image; diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 40a57a321d8..4c01c75e06c 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -325,7 +325,7 @@ struct UVPackIsland_Params { }; /** - * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image. + * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image. */ bool uv_coords_isect_udim(const struct Image *image, const int udim_grid[2], diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index ad5aeb1c29f..05acdac3597 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1028,7 +1028,7 @@ void ui_draw_but_CURVE(struct ARegion *region, const struct uiWidgetColors *wcol, const rcti *rect); /** - * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE. + * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE. */ void ui_draw_but_CURVEPROFILE(struct ARegion *region, uiBut *but, diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index d93edd2776b..d469efbd0a1 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -359,7 +359,12 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) /* copy data stored in job descriptor */ bkr.scene = scene; bkr.bake_margin = scene->r.bake_margin; - bkr.bake_margin_type = scene->r.bake_margin_type; + if (scene->r.bake_mode == RE_BAKE_NORMALS) { + bkr.bake_margin_type = R_BAKE_EXTEND; + } + else { + bkr.bake_margin_type = scene->r.bake_margin_type; + } bkr.mode = scene->r.bake_mode; bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkr.bias = scene->r.bake_biasdist; @@ -404,7 +409,12 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) /* backup scene settings, so their changing in UI would take no effect on baker */ bkj->scene = scene; bkj->bake_margin = scene->r.bake_margin; - bkj->bake_margin_type = scene->r.bake_margin_type; + if (scene->r.bake_mode == RE_BAKE_NORMALS) { + bkj->bake_margin_type = R_BAKE_EXTEND; + } + else { + bkj->bake_margin_type = scene->r.bake_margin_type; + } bkj->mode = scene->r.bake_mode; bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index fec87fbfa95..3060a1ecf62 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1670,6 +1670,11 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) { bkr->save_mode = R_BAKE_SAVE_INTERNAL; } + + if (((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT)) || + bkr->pass_type == SCE_PASS_UV) { + bkr->margin_type = R_BAKE_EXTEND; + } } static int bake_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/render/render_intern.hh b/source/blender/editors/render/render_intern.hh index 85d917ae8e8..a4056f3dab3 100644 --- a/source/blender/editors/render/render_intern.hh +++ b/source/blender/editors/render/render_intern.hh @@ -35,6 +35,8 @@ void SCENE_OT_view_layer_add_aov(struct wmOperatorType *ot); void SCENE_OT_view_layer_remove_aov(struct wmOperatorType *ot); void SCENE_OT_view_layer_add_lightgroup(struct wmOperatorType *ot); void SCENE_OT_view_layer_remove_lightgroup(struct wmOperatorType *ot); +void SCENE_OT_view_layer_add_used_lightgroups(struct wmOperatorType *ot); +void SCENE_OT_view_layer_remove_unused_lightgroups(struct wmOperatorType *ot); void SCENE_OT_light_cache_bake(struct wmOperatorType *ot); void SCENE_OT_light_cache_free(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_ops.cc b/source/blender/editors/render/render_ops.cc index f671b2f950d..def220fb4fc 100644 --- a/source/blender/editors/render/render_ops.cc +++ b/source/blender/editors/render/render_ops.cc @@ -41,6 +41,8 @@ void ED_operatortypes_render() WM_operatortype_append(SCENE_OT_view_layer_remove_aov); WM_operatortype_append(SCENE_OT_view_layer_add_lightgroup); WM_operatortype_append(SCENE_OT_view_layer_remove_lightgroup); + WM_operatortype_append(SCENE_OT_view_layer_add_used_lightgroups); + WM_operatortype_append(SCENE_OT_view_layer_remove_unused_lightgroups); WM_operatortype_append(SCENE_OT_render_view_add); WM_operatortype_append(SCENE_OT_render_view_remove); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 4c885d50b4c..f5bd60df2b4 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -1217,6 +1217,114 @@ void SCENE_OT_view_layer_remove_lightgroup(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name View Layer Add Used Lightgroups Operator + * \{ */ + +static GSet *get_used_lightgroups(Scene *scene) +{ + GSet *used_lightgroups = BLI_gset_str_new(__func__); + + FOREACH_SCENE_OBJECT_BEGIN (scene, ob) { + if (ob->lightgroup && ob->lightgroup->name[0]) { + BLI_gset_add(used_lightgroups, ob->lightgroup->name); + } + } + FOREACH_SCENE_OBJECT_END; + + if (scene->world && scene->world->lightgroup && scene->world->lightgroup->name[0]) { + BLI_gset_add(used_lightgroups, scene->world->lightgroup->name); + } + + return used_lightgroups; +} + +static int view_layer_add_used_lightgroups_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + GSet *used_lightgroups = get_used_lightgroups(scene); + GSET_FOREACH_BEGIN (const char *, used_lightgroup, used_lightgroups) { + if (!BLI_findstring( + &view_layer->lightgroups, used_lightgroup, offsetof(ViewLayerLightgroup, name))) { + BKE_view_layer_add_lightgroup(view_layer, used_lightgroup); + } + } + GSET_FOREACH_END(); + BLI_gset_free(used_lightgroups, nullptr); + + if (scene->nodetree) { + ntreeCompositUpdateRLayers(scene->nodetree); + } + + DEG_id_tag_update(&scene->id, 0); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_view_layer_add_used_lightgroups(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Used Lightgroups"; + ot->idname = "SCENE_OT_view_layer_add_used_lightgroups"; + ot->description = "Add all used Light Groups"; + + /* api callbacks */ + ot->exec = view_layer_add_used_lightgroups_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Layer Remove Unused Lightgroups Operator + * \{ */ + +static int view_layer_remove_unused_lightgroups_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + GSet *used_lightgroups = get_used_lightgroups(scene); + LISTBASE_FOREACH_MUTABLE (ViewLayerLightgroup *, lightgroup, &view_layer->lightgroups) { + if (!BLI_gset_haskey(used_lightgroups, lightgroup->name)) { + BKE_view_layer_remove_lightgroup(view_layer, lightgroup); + } + } + BLI_gset_free(used_lightgroups, nullptr); + + if (scene->nodetree) { + ntreeCompositUpdateRLayers(scene->nodetree); + } + + DEG_id_tag_update(&scene->id, 0); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_view_layer_remove_unused_lightgroups(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Unused Lightgroups"; + ot->idname = "SCENE_OT_view_layer_remove_unused_lightgroups"; + ot->description = "Remove all unused Light Groups"; + + /* api callbacks */ + ot->exec = view_layer_remove_unused_lightgroups_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Light Cache Bake Operator * \{ */ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 50b994be710..30bf23e0987 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -3443,7 +3443,6 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x { bScreen *screen = CTX_wm_screen(C); wmWindow *win = CTX_wm_window(C); - wmWindowManager *wm = CTX_wm_manager(C); ScrArea *area = NULL; @@ -3455,8 +3454,8 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x if (!area) { /* Check all windows except the active one. */ int scr_pos[2]; - wmWindow *r_win = WM_window_find_under_cursor(wm, win, win, xy, scr_pos); - if (r_win) { + wmWindow *r_win = WM_window_find_under_cursor(win, xy, scr_pos); + if (r_win && r_win != win) { win = r_win; screen = WM_window_get_active_screen(win); area = BKE_screen_find_area_xy(screen, spacetype, scr_pos); diff --git a/source/blender/editors/sculpt_paint/paint_canvas.cc b/source/blender/editors/sculpt_paint/paint_canvas.cc index 9a1a61cf3ab..5683e3ff741 100644 --- a/source/blender/editors/sculpt_paint/paint_canvas.cc +++ b/source/blender/editors/sculpt_paint/paint_canvas.cc @@ -19,6 +19,8 @@ #include "WM_toolsystem.h" +#include "ED_paint.h" + namespace blender::ed::sculpt_paint::canvas { static TexPaintSlot *get_active_slot(Object *ob) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 73fc5bd68f3..38905b50c59 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -201,13 +201,11 @@ struct SculptRakeData { float follow_co[3]; }; -/* -Generic thread data. The size of this struct -has gotten a little out of hand; normally we would -split it up, but it might be better to see if we can't -eliminate it altogether after moving to C++ (where -we'll be able to use lambdas). -*/ +/** + * Generic thread data. The size of this struct has gotten a little out of hand; + * normally we would split it up, but it might be better to see if we can't eliminate it + * altogether after moving to C++ (where we'll be able to use lambdas). + */ typedef struct SculptThreadedTaskData { struct bContext *C; struct Sculpt *sd; diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index fe83fade055..e7a713efa14 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -454,7 +454,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, } /* Multiply weight with edge lengths (in the future this will be - cotangent weights or face areas). */ + * cotangent weights or face areas). */ w *= len; /* Build directional weight. */ diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 03ec018fbe8..bc047a00ae1 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -100,7 +100,7 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED( simage->lock = true; simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS; simage->uv_opacity = 1.0f; - simage->overlay.flag = SI_OVERLAY_SHOW_OVERLAYS; + simage->overlay.flag = SI_OVERLAY_SHOW_OVERLAYS | SI_OVERLAY_SHOW_GRID_BACKGROUND; BKE_imageuser_default(&simage->iuser); simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS | IMA_SHOW_MAX_RESOLUTION; diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 433efb79b77..44163cd5ae3 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -117,6 +117,8 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT); */ float2 space_node_group_offset(const SpaceNode &snode); +rctf node_frame_rect_inside(const bNode &node); + int node_get_resize_cursor(NodeResizeDirection directions); /** * Usual convention here would be #node_socket_get_color(), diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 50c85a907a6..67bc0e91053 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -47,6 +47,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_query.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" @@ -810,6 +811,13 @@ static void id_override_library_create_fn(bContext *C, void *user_data) { BLI_assert(TSE_IS_REAL_ID(tselem)); + + /* We can only safely apply this operation on one item at a time, so only do it on the active + * one. */ + if ((tselem->flag & TSE_ACTIVE) == 0) { + return; + } + ID *id_root_reference = tselem->id; OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; @@ -1000,6 +1008,23 @@ static void id_override_library_create_hierarchy_post_process(bContext *C, FOREACH_MAIN_ID_END; } +static void id_override_library_toggle_flag_fn(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *user_data) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + ID *id = tselem->id; + + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + const uint flag = POINTER_AS_UINT(user_data); + id->override_library->flag ^= flag; + } +} + static void id_override_library_reset_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -1017,10 +1042,10 @@ static void id_override_library_reset_fn(bContext *C, Main *bmain = CTX_data_main(C); if (do_hierarchy) { - BKE_lib_override_library_id_hierarchy_reset(bmain, id_root); + BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false); } else { - BKE_lib_override_library_id_reset(bmain, id_root); + BKE_lib_override_library_id_reset(bmain, id_root, false); } WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr); @@ -1072,40 +1097,75 @@ static void id_override_library_resync_fn(bContext *C, } } -static void id_override_library_delete_fn(bContext *C, - ReportList *UNUSED(reports), - Scene *UNUSED(scene), - TreeElement *te, - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) +static void id_override_library_clear_hierarchy_fn(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { - Main *bmain = CTX_data_main(C); + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); + return; + } - id_root->tag |= LIB_TAG_DOIT; + Main *bmain = CTX_data_main(C); - /* Tag all linked parents in tree hierarchy to be also overridden. */ - while ((te = te->parent) != nullptr) { - if (!TSE_IS_REAL_ID(te->store_elem)) { - continue; - } - if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { - break; - } - te->store_elem->id->tag |= LIB_TAG_DOIT; + id_root->tag |= LIB_TAG_DOIT; + + /* Tag all override parents in tree hierarchy to be also processed. */ + while ((te = te->parent) != nullptr) { + if (!TSE_IS_REAL_ID(te->store_elem)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { + break; } + te->store_elem->id->tag |= LIB_TAG_DOIT; + } - BKE_lib_override_library_delete(bmain, id_root); + BKE_lib_override_library_delete(bmain, id_root); - WM_event_add_notifier(C, NC_WINDOW, nullptr); + WM_event_add_notifier(C, NC_WINDOW, nullptr); +} + +static void id_override_library_clear_single_fn(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + Main *bmain = CTX_data_main(C); + ID *id = tselem->id; + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot clear embedded library override id '%s', only overrides of real " + "data-blocks can be directly deleted", + id->name); + return; + } + + /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy), + * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system + * override. */ + if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) { + BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE); + BKE_id_delete(bmain, id); } else { - CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); + BKE_lib_override_library_id_reset(bmain, id, true); } + + WM_event_add_notifier(C, NC_WINDOW, nullptr); } static void id_fake_user_set_fn(bContext *UNUSED(C), @@ -1751,11 +1811,11 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob); -typedef struct ObjectEditData { +using ObjectEditData = struct ObjectEditData { GSet *objects_set; bool is_liboverride_allowed; bool is_liboverride_hierarchy_root_allowed; -} ObjectEditData; +}; static void outliner_do_object_delete(bContext *C, ReportList *reports, @@ -1903,11 +1963,13 @@ enum eOutlinerIdOpTypes { OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE, - OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1937,13 +1999,20 @@ static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, "OVERRIDE_LIBRARY_CREATE", 0, - "Make Library Override", - "Make a local override of this linked data-block"}, + "Make Library Override Single", + "Make a single, out-of-hierarchy local override of this linked data-block - only applies to " + "active Outliner item"}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, "OVERRIDE_LIBRARY_CREATE_HIERARCHY", 0, "Make Library Override Hierarchy", - "Make a local override of this linked data-block, and its hierarchy of dependencies"}, + "Make a local override of this linked data-block, and its hierarchy of dependencies - only " + "applies to active Outliner item"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE, + "OVERRIDE_LIBRARY_MAKE_EDITABLE", + 0, + "Make Library Override Editable", + "Make the library override data-block editable"}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, "OVERRIDE_LIBRARY_RESET", 0, @@ -1967,12 +2036,18 @@ static const EnumPropertyItem prop_id_op_types[] = { "Rebuild this local override from its linked reference, as well as its hierarchy of " "dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting " "overrides on data-blocks pointer properties)"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, - "OVERRIDE_LIBRARY_DELETE_HIERARCHY", + {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY, + "OVERRIDE_LIBRARY_CLEAR_HIERARCHY", 0, - "Delete Library Override Hierarchy", + "Clear Library Override Hierarchy", "Delete this local override (including its hierarchy of override dependencies) and relink " "its usages to the linked data-blocks"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE, + "OVERRIDE_LIBRARY_CLEAR_SINGLE", + 0, + "Clear Single Library Override", + "Delete this local override if possible, else reset it and mark it as non editable, and " + "relink its usages to the linked data-blocks"}, {0, "", 0, nullptr, nullptr}, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, @@ -2016,11 +2091,19 @@ static bool outliner_id_operation_item_poll(bContext *C, return true; } return false; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: + if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { + if (tselem->id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) { + return true; + } + } + return false; case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: - case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { return true; } @@ -2201,6 +2284,18 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Overridden Data Hierarchy"); break; } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_toggle_flag_fn, + POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED)); + + ED_undo_push(C, "Make Overridden Data Editable"); + break; + } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: { OutlinerLibOverrideData override_data{}; outliner_do_libdata_operation(C, @@ -2253,17 +2348,26 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Resync Overridden Data Hierarchy"); break; } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: { outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, - id_override_library_delete_fn, - &override_data); - ED_undo_push(C, "Delete Overridden Data Hierarchy"); + id_override_library_clear_hierarchy_fn, + nullptr); + ED_undo_push(C, "Clear Overridden Data Hierarchy"); + break; + } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_clear_single_fn, + nullptr); + ED_undo_push(C, "Clear Overridden Data Hierarchy"); break; } case OUTLINER_IDOP_SINGLE: { diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 990d3680057..c7f086e7d4b 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -66,6 +66,9 @@ typedef struct TransSeq { /* Initial rect of the view2d, used for computing offset during edge panning */ rctf initial_v2d_cur; View2DEdgePanData edge_pan; + + /* Strips that aren't selected, but their position entirely depends on transformed strips. */ + SeqCollection *time_dependent_strips; } TransSeq; /* -------------------------------------------------------------------- */ @@ -256,6 +259,7 @@ static void free_transform_custom_data(TransCustomData *custom_data) { if ((custom_data->data != NULL) && custom_data->use_free) { TransSeq *ts = custom_data->data; + SEQ_collection_free(ts->time_dependent_strips); MEM_freeN(ts->tdseq); MEM_freeN(custom_data->data); custom_data->data = NULL; @@ -630,10 +634,114 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c free_transform_custom_data(custom_data); } -void createTransSeqData(TransInfo *t) +static SeqCollection *query_selected_strips_no_handles(ListBase *seqbase) { -#define XXX_DURIAN_ANIM_TX_HACK + SeqCollection *strips = SEQ_collection_create(__func__); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if ((seq->flag & SELECT) != 0 && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) { + SEQ_collection_append_strip(seq, strips); + } + } + return strips; +} + +typedef enum SeqInputSide { + SEQ_INPUT_LEFT = -1, + SEQ_INPUT_RIGHT = 1, +} SeqInputSide; +static Sequence *effect_input_get(Sequence *effect, SeqInputSide side) +{ + Sequence *input = effect->seq1; + if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) { + input = effect->seq2; + } + return input; +} + +static Sequence *effect_base_input_get(Sequence *effect, SeqInputSide side) +{ + Sequence *input = effect, *seq_iter = effect; + while (seq_iter != NULL) { + input = seq_iter; + seq_iter = effect_input_get(seq_iter, side); + } + return input; +} + +/* Strips that aren't selected, but their position entirely depends on transformed strips. + * This collection is used to offset animation.*/ +static SeqCollection *query_time_dependent_strips_strips(TransInfo *t) +{ + ListBase *seqbase = seqbase_active_get(t); + + /* Query dependent strips where used strips do not have handles selected. + * If all inputs of any effect even indirectly(through another effect) points to selected strip, + * it's position will change. */ + + SeqCollection *strips_no_handles = query_selected_strips_no_handles(seqbase); + /* Selection is needed as reference for related strips. */ + SeqCollection *dependent = SEQ_collection_duplicate(strips_no_handles); + SEQ_collection_expand(seqbase, strips_no_handles, SEQ_query_strip_effect_chain); + bool strip_added = true; + + while (strip_added) { + strip_added = false; + + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, strips_no_handles) { + if (SEQ_collection_has_strip(seq, dependent)) { + continue; /* Strip is already in collection, skip it. */ + } + + /* If both seq1 and seq2 exist, both must be selected. */ + if (seq->seq1 && SEQ_collection_has_strip(seq->seq1, dependent)) { + if (seq->seq2 && !SEQ_collection_has_strip(seq->seq2, dependent)) { + continue; + } + strip_added = true; + SEQ_collection_append_strip(seq, dependent); + } + } + } + + SEQ_collection_free(strips_no_handles); + + /* Query dependent strips where used strips do have handles selected. + * If any 2-input effect changes position because handles were moved, animation should be offset. + * With single input effect, it is less likely desirable to move animation. */ + + SeqCollection *selected_strips = SEQ_query_selected_strips(seqbase); + SEQ_collection_expand(seqbase, selected_strips, SEQ_query_strip_effect_chain); + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, selected_strips) { + /* Check only 2 input effects. */ + if (seq->seq1 == NULL || seq->seq2 == NULL) { + continue; + } + + /* Find immediate base inputs(left and right side). */ + Sequence *input_left = effect_base_input_get(seq, SEQ_INPUT_LEFT); + Sequence *input_right = effect_base_input_get(seq, SEQ_INPUT_RIGHT); + + if ((input_left->flag & SEQ_RIGHTSEL) != 0 && (input_right->flag & SEQ_LEFTSEL) != 0) { + SEQ_collection_append_strip(seq, dependent); + } + } + SEQ_collection_free(selected_strips); + + /* Remove all non-effects. */ + SEQ_ITERATOR_FOREACH (seq, dependent) { + if (SEQ_transform_sequence_can_be_translated(seq)) { + SEQ_collection_remove_strip(seq, dependent); + } + } + + return dependent; +} + +void createTransSeqData(TransInfo *t) +{ Scene *scene = t->scene; Editing *ed = SEQ_editing_get(t->scene); TransData *td = NULL; @@ -653,26 +761,6 @@ void createTransSeqData(TransInfo *t) tc->custom.type.free_cb = freeSeqData; t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA); -#ifdef XXX_DURIAN_ANIM_TX_HACK - { - Sequence *seq; - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - /* hack */ - if ((seq->flag & SELECT) == 0 && seq->type & SEQ_TYPE_EFFECT) { - Sequence *seq_user; - int i; - for (i = 0; i < 3; i++) { - seq_user = *((&seq->seq1) + i); - if (seq_user && (seq_user->flag & SELECT) && !(seq_user->flag & SEQ_LOCK) && - !(seq_user->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL))) { - seq->flag |= SELECT; - } - } - } - } - } -#endif - count = SeqTransCount(t, ed->seqbasep); /* allocate memory for data */ @@ -712,7 +800,7 @@ void createTransSeqData(TransInfo *t) } } -#undef XXX_DURIAN_ANIM_TX_HACK + ts->time_dependent_strips = query_time_dependent_strips_strips(t); } /** \} */ @@ -771,7 +859,8 @@ static void flushTransSeq(TransInfo *t) /* Editing null check already done */ ListBase *seqbasep = seqbase_active_get(t); - int a, new_frame; + int a, new_frame, offset; + TransData *td = NULL; TransData2D *td2d = NULL; TransDataSeq *tdsq = NULL; @@ -779,6 +868,15 @@ static void flushTransSeq(TransInfo *t) TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + /* This is calculated for offsetting animation of effects that change position with inputs. + * Maximum(positive or negative) value is used, because individual strips can be clamped. This + * works fairly well in most scenarios, but there can be some edge cases. + * + * Better solution would be to store effect position and calculate real offset. However with many + * (>5) effects in chain, there is visible lag in strip position update, because during + * recalculation, hierarchy is not taken into account. */ + int max_offset = 0; + /* Flush to 2D vector from internally used 3D vector. */ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) { tdsq = (TransDataSeq *)td->extra; @@ -788,31 +886,49 @@ static void flushTransSeq(TransInfo *t) new_frame = round_fl_to_int(loc[0]); switch (tdsq->sel_flag) { - case SELECT: + case SELECT: { if (SEQ_transform_sequence_can_be_translated(seq)) { - const int offset = new_frame - tdsq->start_offset - seq->start; + offset = new_frame - tdsq->start_offset - seq->start; SEQ_transform_translate_sequence(t->scene, seq, offset); + if (abs(offset) > abs(max_offset)) { + max_offset = offset; + } } seq->machine = round_fl_to_int(loc[1]); CLAMP(seq->machine, 1, MAXSEQ); break; - - case SEQ_LEFTSEL: /* No vertical transform. */ + } + case SEQ_LEFTSEL: { /* No vertical transform. */ + int old_startdisp = seq->startdisp; SEQ_transform_set_left_handle_frame(seq, new_frame); SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); SEQ_transform_fix_single_image_seq_offsets(seq); SEQ_time_update_sequence(t->scene, seqbasep, seq); + if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) { + max_offset = seq->startdisp - old_startdisp; + } break; - case SEQ_RIGHTSEL: /* No vertical transform. */ + } + case SEQ_RIGHTSEL: { /* No vertical transform. */ + int old_enddisp = seq->enddisp; SEQ_transform_set_right_handle_frame(seq, new_frame); SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); SEQ_transform_fix_single_image_seq_offsets(seq); SEQ_time_update_sequence(t->scene, seqbasep, seq); + if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) { + max_offset = seq->enddisp - old_enddisp; + } break; + } } } - /* Update all effects. */ + /* Update animation for effects. */ + SEQ_ITERATOR_FOREACH (seq, ts->time_dependent_strips) { + SEQ_offset_animdata(t->scene, seq, max_offset); + } + + /* Update effect length and position. */ if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) { for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->seq1 || seq->seq2 || seq->seq3) { diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h index 5ab6fc794f9..47b3e827439 100644 --- a/source/blender/freestyle/intern/view_map/Interface1D.h +++ b/source/blender/freestyle/intern/view_map/Interface1D.h @@ -27,31 +27,46 @@ using namespace std; namespace Freestyle { // Integration method -/** The different integration methods that can be invoked to integrate into a single value the set +/** + * The different integration methods that can be invoked to integrate into a single value the set * of values obtained from each 0D element of a 1D element. */ typedef enum { - MEAN, /**< The value computed for the 1D element is the mean of the values obtained for the 0D - elements. */ - MIN, /**< The value computed for the 1D element is the minimum of the values obtained for the 0D - elements. */ - MAX, /**< The value computed for the 1D element is the maximum of the values obtained for the 0D - elements. */ - FIRST, /**< The value computed for the 1D element is the first of the values obtained for the 0D - elements. */ - LAST, /**< The value computed for the 1D element is the last of the values obtained for the 0D - elements. */ + /** + * The value computed for the 1D element is the mean of the values obtained for the 0D elements. + */ + MEAN, + /** + * The value computed for the 1D element is the minimum of the values obtained for the 0D + * elements. + */ + MIN, + /** + * The value computed for the 1D element is the maximum of the values obtained for the 0D + * elements. + */ + MAX, + /** + * The value computed for the 1D element is the first of the values obtained for the 0D + * elements. + */ + FIRST, + /** + * The value computed for the 1D element is the last of the values obtained for the 0D + * elements. + */ + LAST, } IntegrationType; -/** Returns a single value from a set of values evaluated at each 0D element of this 1D element. - * \param fun: - * The UnaryFunction0D used to compute a value at each Interface0D. - * \param it: - * The Interface0DIterator used to iterate over the 0D elements of this 1D element. The - * integration will occur over the 0D elements starting from the one pointed by it. \param it_end: - * The Interface0DIterator pointing the end of the 0D elements of the 1D element. - * \param integration_type: - * The integration method used to compute a single value from a set of values. +/** + * Returns a single value from a set of values evaluated at each 0D element of this 1D element. + * + * \param fun: The UnaryFunction0D used to compute a value at each Interface0D. + * \param it: The Interface0DIterator used to iterate over the 0D elements of this 1D element. + * The integration will occur over the 0D elements starting from the one pointed by it. + * \param it_end: The Interface0DIterator pointing the end of the 0D elements of the 1D element. + * \param integration_type: The integration method used to compute a single value from a set of + * values. * \return the single value obtained for the 1D element. */ template<class T> diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index ed587a87695..e0ccd2a482d 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -20,7 +20,7 @@ namespace blender::fn { * 2. single output (SO) of type Out1 * * This example creates a function that adds 10 to the incoming values: - * CustomMF_SI_SO<int, int> fn("add 10", [](int value) { return value + 10; }); + * `CustomMF_SI_SO<int, int> fn("add 10", [](int value) { return value + 10; });` */ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunction { private: diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c index d9881f5b7ae..efbec4222aa 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c @@ -218,10 +218,12 @@ static void apply_stroke_envelope( max_ii(0, i + j - spread_left); const int i2 = is_cyclic ? (i + j + spread_right) % gps->totpoints : min_ii(gps->totpoints - 1, i + j + spread_right); - /*bool side = dot_v3v3(&old_points[i1].x, plane_no) < dot_v3v3(plane_no, &old_points[i2].x); +#if 0 + bool side = dot_v3v3(&old_points[i1].x, plane_no) < dot_v3v3(plane_no, &old_points[i2].x); if (side) { continue; - }*/ + } +#endif float lambda = line_plane_factor_v3( &point->x, plane_no, &old_points[i1].x, &old_points[i2].x); if (lambda <= 0.0f || lambda >= 1.0f) { diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h index 0f922dca47f..24d80e99c38 100644 --- a/source/blender/io/usd/intern/usd_reader_material.h +++ b/source/blender/io/usd/intern/usd_reader_material.h @@ -40,7 +40,7 @@ struct NodePlacementContext { /* Converts USD materials to Blender representation. */ /** - By default, the #USDMaterialReader creates a Blender material with + * By default, the #USDMaterialReader creates a Blender material with * the same name as the USD material. If the USD material has a * #UsdPreviewSurface source, the Blender material's viewport display * color, roughness and metallic properties are set to the corresponding diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index eb9c2f13c29..f78ef334d4d 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -425,11 +425,25 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, /** * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the - * parameter range are inserted. + * parameter range are inserted. However for curves with endpoint flag, + * first degree+1 numbers are zeroes, and last degree+1 numbers are ones */ + + const short flagsu = obj_nurbs_data.get_nurbs_flagu(spline_idx); + const bool cyclic = flagsu & CU_NURB_CYCLIC; + const bool endpoint = !cyclic && (flagsu & CU_NURB_ENDPOINT); fh.write<eOBJSyntaxElement::nurbs_parameter_begin>(); for (int i = 1; i <= total_control_points + 2; i++) { - fh.write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i / (total_control_points + 2 + 1)); + float parm = 1.0f * i / (total_control_points + 2 + 1); + if (endpoint) { + if (i <= nurbs_degree) { + parm = 0; + } + else if (i > total_control_points + 2 - nurbs_degree) { + parm = 1; + } + } + fh.write<eOBJSyntaxElement::nurbs_parameters>(parm); } fh.write<eOBJSyntaxElement::nurbs_parameter_end>(); diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 61699c78ace..8599b38d55b 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -265,7 +265,7 @@ o abcdef o 012345678901234567890123456789abcd o 123 curv 0.0 1.0 -parm 0.0 +parm u 0.0 )"; ASSERT_EQ(got_string, expected); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index e3a6f50531d..17d783d3ebf 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -349,8 +349,10 @@ typedef struct ID_Runtime_Remap { int status; /** During ID remapping the number of skipped use cases that refcount the data-block. */ int skipped_refcounted; - /** During ID remapping the number of direct use cases that could be remapped (e.g. obdata when -in edit mode). */ + /** + * During ID remapping the number of direct use cases that could be remapped + * (e.g. obdata when in edit mode). + */ int skipped_direct; /** During ID remapping, the number of indirect use cases that could not be remapped. */ int skipped_indirect; diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h index 0aa4ebc61d0..bb53dbafdc8 100644 --- a/source/blender/makesdna/DNA_curves_types.h +++ b/source/blender/makesdna/DNA_curves_types.h @@ -51,8 +51,8 @@ typedef enum KnotsMode { /** Method used to calculate the normals of a curve's evaluated points. */ typedef enum NormalMode { - NORMAL_MODE_Z_UP = 0, - NORMAL_MODE_MINIMUM_TWIST = 1, + NORMAL_MODE_MINIMUM_TWIST = 0, + NORMAL_MODE_Z_UP = 1, } NormalMode; /** @@ -84,7 +84,7 @@ typedef struct CurvesGeometry { /** * The start index of each curve in the point data. The size of each curve can be calculated by * subtracting the offset from the next offset. That is valid even for the last curve because - * this array is allocated with a length one larger than the number of splines. This is allowed + * this array is allocated with a length one larger than the number of curves. This is allowed * to be null when there are no curves. * * \note This is *not* stored in #CustomData because its size is one larger than #curve_data. diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 806c989100d..bcf54ee47a0 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1318,6 +1318,7 @@ typedef enum eSpaceImage_Flag { typedef enum eSpaceImageOverlay_Flag { SI_OVERLAY_SHOW_OVERLAYS = (1 << 0), + SI_OVERLAY_SHOW_GRID_BACKGROUND = (1 << 1), } eSpaceImageOverlay_Flag; /** Keep in sync with `STEPS_LEN` in `grid_frag.glsl`. */ diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 118589332ea..794f08d850e 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -481,7 +481,7 @@ void RNA_def_camera(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_lens_unit_items[] = { - {0, "MILLIMETERS", 0, "Millimeters", "Specify the lens in millimeters"}, + {0, "MILLIMETERS", 0, "Millimeters", "Specify focal length of the lens in millimeters"}, {CAM_ANGLETOGGLE, "FOV", 0, @@ -564,7 +564,7 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "lens"); RNA_def_property_range(prop, 1.0f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 100, 4); - RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera lens value in millimeters"); + RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera focal length value in millimeters"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update"); prop = RNA_def_property(srna, "sensor_width", PROP_FLOAT, PROP_DISTANCE_CAMERA); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index ba040f88b55..b941245bcfc 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -365,9 +365,9 @@ void rna_ViewLayer_active_lightgroup_index_range( int rna_ViewLayer_active_lightgroup_index_get(PointerRNA *ptr); void rna_ViewLayer_active_lightgroup_index_set(PointerRNA *ptr, int value); /** - * Set `r_rna_path` with the base view-layer path. - * `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`. - * \return actual length of the generated RNA path. + * Set `r_rna_path` with the base view-layer path. + * `rna_path_buffer_size` should be at least `sizeof(ViewLayer.name) * 3`. + * \return actual length of the generated RNA path. */ size_t rna_ViewLayer_path_buffer_get(struct ViewLayer *view_layer, char *r_rna_path, diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 24d50a0300f..4db438f04b4 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -30,14 +30,16 @@ typedef struct IDProperty IDProperty; /* Function Callbacks */ -/** Update callback for an RNA property. +/** + * Update callback for an RNA property. * - * \note This is NOT called automatically when writing into the property, it needs to be called + * \note This is NOT called automatically when writing into the property, it needs to be called * manually (through #RNA_property_update or #RNA_property_update_main) when needed. * - * \param bmain: the Main data-base to which `ptr` data belongs. - * \param active_scene: The current active scene (may be NULL in some cases). - * \param ptr: The RNA pointer data to update. */ + * \param bmain: the Main data-base to which `ptr` data belongs. + * \param active_scene: The current active scene (may be NULL in some cases). + * \param ptr: The RNA pointer data to update. + */ typedef void (*UpdateFunc)(struct Main *bmain, struct Scene *active_scene, struct PointerRNA *ptr); typedef void (*ContextPropUpdateFunc)(struct bContext *C, struct PointerRNA *ptr, diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index a74019f9569..d2b8eb203aa 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3497,7 +3497,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Display Faces", "Display faces over the image"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); - prop = RNA_def_property(srna, "tile_grid_shape", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "tile_grid_shape", PROP_INT, PROP_XYZ); RNA_def_property_int_sdna(prop, NULL, "tile_grid_shape"); RNA_def_property_array(prop, 2); RNA_def_property_int_default(prop, 1); @@ -5264,6 +5264,11 @@ static void rna_def_space_image_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SI_OVERLAY_SHOW_OVERLAYS); RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like UV Maps and Metadata"); + + prop = RNA_def_property(srna, "show_grid_background", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SI_OVERLAY_SHOW_GRID_BACKGROUND); + RNA_def_property_ui_text(prop, "Display Background", "Show the grid background and borders"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); } static void rna_def_space_image(BlenderRNA *brna) diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index c1f0f043c92..e58c1068368 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -28,15 +28,15 @@ const FloatMathOperationInfo *get_float_compare_operation_info(int operation); /** * This calls the `callback` with two arguments: - * 1. The math function that takes a float as input and outputs a new float. - * 2. A #FloatMathOperationInfo struct reference. + * 1. The math function that takes a float as input and outputs a new float. + * 2. A #FloatMathOperationInfo struct reference. * Returns true when the callback has been called, otherwise false. * * The math function that is passed to the callback is actually a lambda function that is different * for every operation. Therefore, if the callback is templated on the math function, it will get * instantiated for every operation separately. This has two benefits: - * - The compiler can optimize the callback for every operation separately. - * - A static variable declared in the callback will be generated for every operation separately. + * - The compiler can optimize the callback for every operation separately. + * - A static variable declared in the callback will be generated for every operation separately. * * If separate instantiations are not desired, the callback can also take a function pointer with * the following signature as input instead: float (*math_function)(float a). diff --git a/source/blender/nodes/NOD_socket_search_link.hh b/source/blender/nodes/NOD_socket_search_link.hh index 7a1aff13020..8d80da229a7 100644 --- a/source/blender/nodes/NOD_socket_search_link.hh +++ b/source/blender/nodes/NOD_socket_search_link.hh @@ -120,8 +120,8 @@ class GatherLinkSearchOpParams { /** * This callback can be used for a node type when a few things are true about its inputs. * To avoid creating more boilerplate, it is the default callback for node types. - * - Either all declared sockets are visible in the default state of the node, *OR* the node's - * type's declaration has been extended with #make_available functions for those sockets. + * - Either all declared sockets are visible in the default state of the node, *OR* the node's + * type's declaration has been extended with #make_available functions for those sockets. * * If a node type does not meet these criteria, the function will do nothing in a release build. * In a debug build, an assert will most likely be hit. diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index be17918609f..5d97720a4f8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -59,11 +59,10 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves) { curves.ensure_evaluated_lengths(); const VArray<int8_t> types = curves.curve_types(); - const VArray<int> resolution = curves.resolution(); + const VArray<int> resolutions = curves.resolution(); const VArray<bool> cyclic = curves.cyclic(); Array<float> result(curves.points_num()); - VArray<int> resolutions = curves.resolution(); threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) { for (const int i_curve : range) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 5a2c32a6c8e..2894e608819 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -627,7 +627,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set, calc_boundaries(mesh_in, vertex_types, edge_types); /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped * over in order of their indices, the polygon's indices will be sorted in ascending order. - (This can change once they are sorted using `sort_vertex_polys`). */ + * (This can change once they are sorted using `sort_vertex_polys`). */ Array<Vector<int>> vertex_poly_indices(mesh_in.totvert); Array<Array<int>> vertex_shared_edges(mesh_in.totvert); Array<Array<int>> vertex_corners(mesh_in.totvert); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 435dd969c03..039d6b69585 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -2,7 +2,7 @@ #include "BLI_task.hh" -#include "BKE_spline.hh" +#include "BKE_curves.hh" #include "node_geometry_util.hh" @@ -13,65 +13,54 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Tangent")).field_source(); } -static void calculate_bezier_tangents(const BezierSpline &spline, MutableSpan<float3> tangents) +static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curves) { - Span<int> offsets = spline.control_point_offsets(); - Span<float3> evaluated_tangents = spline.evaluated_tangents(); - for (const int i : IndexRange(spline.size())) { - tangents[i] = evaluated_tangents[offsets[i]]; - } -} + const VArray<int8_t> types = curves.curve_types(); + const VArray<int> resolutions = curves.resolution(); + const VArray<bool> cyclic = curves.cyclic(); + const Span<float3> positions = curves.positions(); -static void calculate_poly_tangents(const PolySpline &spline, MutableSpan<float3> tangents) -{ - tangents.copy_from(spline.evaluated_tangents()); -} + const Span<float3> evaluated_tangents = curves.evaluated_tangents(); -/** - * Because NURBS control points are not necessarily on the path, the tangent at the control points - * is not well defined, so create a temporary poly spline to find the tangents. This requires extra - * copying currently, but may be more efficient in the future if attributes have some form of CoW. - */ -static void calculate_nurbs_tangents(const NURBSpline &spline, MutableSpan<float3> tangents) -{ - PolySpline poly_spline; - poly_spline.resize(spline.size()); - poly_spline.positions().copy_from(spline.positions()); - tangents.copy_from(poly_spline.evaluated_tangents()); -} + Array<float3> results(curves.points_num()); -static Array<float3> curve_tangent_point_domain(const CurveEval &curve) -{ - Span<SplinePtr> splines = curve.splines(); - Array<int> offsets = curve.control_point_offsets(); - const int total_size = offsets.last(); - Array<float3> tangents(total_size); - - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - const Spline &spline = *splines[i]; - MutableSpan spline_tangents{tangents.as_mutable_span().slice(offsets[i], spline.size())}; - switch (splines[i]->type()) { - case CURVE_TYPE_BEZIER: { - calculate_bezier_tangents(static_cast<const BezierSpline &>(spline), spline_tangents); + threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) { + for (const int i_curve : range) { + const IndexRange points = curves.points_for_curve(i_curve); + const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve); + + MutableSpan<float3> curve_tangents = results.as_mutable_span().slice(points); + + switch (types[i_curve]) { + case CURVE_TYPE_CATMULL_ROM: { + Span<float3> tangents = evaluated_tangents.slice(evaluated_points); + const int resolution = resolutions[i_curve]; + for (const int i : IndexRange(points.size())) { + curve_tangents[i] = tangents[resolution * i]; + } break; } - case CURVE_TYPE_POLY: { - calculate_poly_tangents(static_cast<const PolySpline &>(spline), spline_tangents); + case CURVE_TYPE_POLY: + curve_tangents.copy_from(evaluated_tangents.slice(evaluated_points)); break; - } - case CURVE_TYPE_NURBS: { - calculate_nurbs_tangents(static_cast<const NURBSpline &>(spline), spline_tangents); + case CURVE_TYPE_BEZIER: { + Span<float3> tangents = evaluated_tangents.slice(evaluated_points); + curve_tangents.first() = tangents.first(); + const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve); + for (const int i : IndexRange(points.size()).drop_front(1)) { + curve_tangents[i] = tangents[offsets[i - 1]]; + } break; } - case CURVE_TYPE_CATMULL_ROM: { - BLI_assert_unreachable(); + case CURVE_TYPE_NURBS: { + const Span<float3> curve_positions = positions.slice(points); + bke::curves::poly::calculate_tangents(curve_positions, cyclic[i_curve], curve_tangents); break; } } } }); - return tangents; + return results; } static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, @@ -80,19 +69,25 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp if (!component.has_curves()) { return {}; } - const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); + + const Curves &curves_id = *component.get_for_read(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + + const VArray<int8_t> types = curves.curve_types(); + if (curves.is_single_type(CURVE_TYPE_POLY)) { + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain); + } + + Array<float3> tangents = curve_tangent_point_domain(curves); if (domain == ATTR_DOMAIN_POINT) { - Array<float3> tangents = curve_tangent_point_domain(*curve); return VArray<float3>::ForContainer(std::move(tangents)); } if (domain == ATTR_DOMAIN_CURVE) { - Array<float3> point_tangents = curve_tangent_point_domain(*curve); return component.attribute_try_adapt_domain<float3>( - VArray<float3>::ForContainer(std::move(point_tangents)), - ATTR_DOMAIN_POINT, - ATTR_DOMAIN_CURVE); + VArray<float3>::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h index 6bedf533af1..7c0707477da 100644 --- a/source/blender/python/BPY_extern_run.h +++ b/source/blender/python/BPY_extern_run.h @@ -11,7 +11,7 @@ * strings more cumbersome as otherwise small expressions become multi-line code-blocks. * Optional (ignored when NULL), otherwise this is a NULL terminated array of module names. * - Failure to import any modules prevents any further execution. + * Failure to import any modules prevents any further execution. * * - `err_info` #BPy_RunErrInfo is passed to some functions so errors can be forwarded to the UI. * Option (when NULL errors are printed to the `stdout` and cleared). diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 2ce1da81a2a..748a501ef76 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -189,7 +189,7 @@ static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject } /* Worst case we gain one extra byte (besides null-terminator) by changing - "Left" to "Right", because only the first appearance of "Left" gets replaced. */ + * "Left" to "Right", because only the first appearance of "Left" gets replaced. */ const size_t size = name_src_len + 2; char *name_dst = PyMem_MALLOC(size); const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size); diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 5f4916e640c..e1ff0ff64b3 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -49,10 +49,11 @@ * Function: * All images created during rendering are added to cache, even if the cache is already full. * This is because: - * - one image may be needed multiple times during rendering. - * - keeping the last rendered frame allows us for faster re-render when user edits strip in stack - * - we can decide if we keep frame only when it's completely rendered. Otherwise we risk having - * "holes" in the cache, which can be annoying + * - One image may be needed multiple times during rendering. + * - Keeping the last rendered frame allows us for faster re-render when user edits strip in stack. + * - We can decide if we keep frame only when it's completely rendered. Otherwise we risk having + * "holes" in the cache, which can be annoying. + * * If the cache is full all entries for pending frame will have is_temp_cache set. * * Linking: We use links to reduce number of iterations over entries needed to manage cache. diff --git a/source/tools b/source/tools -Subproject 26bc78162ec89f21453ce3ded7b999bc6649f32 +Subproject 1e658ca996f11e5ff3398d89bd81f5b719304a5 |