Grease Pencil: Set Layers' 'Use Lights' Default to False #104550

Closed
Kevin C. Burke wants to merge 14 commits from (deleted):main into main

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

4
.gitmodules vendored
View File

@ -2,15 +2,19 @@
path = release/scripts/addons
url = ../blender-addons.git
branch = main
ignore = all
[submodule "release/scripts/addons_contrib"]
path = release/scripts/addons_contrib
url = ../blender-addons-contrib.git
branch = main
ignore = all
[submodule "release/datafiles/locale"]
path = release/datafiles/locale
url = ../blender-translations.git
branch = main
ignore = all
[submodule "source/tools"]
path = source/tools
url = ../blender-dev-tools.git
branch = main
ignore = all

View File

@ -105,6 +105,7 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
}
case METAL_GPU_AMD: {
max_threads_per_threadgroup = 128;
use_metalrt = info.use_metalrt;
break;
}
case METAL_GPU_APPLE: {

View File

@ -613,7 +613,6 @@ url_manual_mapping = (
("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"),
("bpy.ops.geometry.color_attribute_render_set*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-render-set"),
("bpy.ops.mesh.customdata_crease_vertex_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-crease-vertex-clear"),
("bpy.types.brush.html#bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-html-bpy-types-brush-jitter"),
("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"),
("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"),
("bpy.types.clothcollisionsettings.collection*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings-collection"),
@ -644,7 +643,7 @@ url_manual_mapping = (
("bpy.types.geometrynodeinputmeshedgevertices*", "modeling/geometry_nodes/mesh/read/edge_vertices.html#bpy-types-geometrynodeinputmeshedgevertices"),
("bpy.types.geometrynodeinputmeshfaceisplanar*", "modeling/geometry_nodes/mesh/read/face_is_planar.html#bpy-types-geometrynodeinputmeshfaceisplanar"),
("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/read/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"),
("bpy.types.geometrynodemeshfacesetboundaries*", "modeling/geometry_nodes/mesh/read/face_set_boundaries.html#bpy-types-geometrynodemeshfacesetboundaries"),
("bpy.types.geometrynodemeshfacesetboundaries*", "modeling/geometry_nodes/mesh/read/face_group_boundaries.html#bpy-types-geometrynodemeshfacesetboundaries"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.lineartgpencilmodifier.use_crease*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease"),
("bpy.types.lineartgpencilmodifier.use_shadow*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-shadow"),
@ -1389,6 +1388,7 @@ url_manual_mapping = (
("bpy.types.functionnodereplacestring*", "modeling/geometry_nodes/utilities/text/replace_string.html#bpy-types-functionnodereplacestring"),
("bpy.types.functionnodeseparatecolor*", "modeling/geometry_nodes/utilities/color/separate_color.html#bpy-types-functionnodeseparatecolor"),
("bpy.types.functionnodevaluetostring*", "modeling/geometry_nodes/utilities/text/value_to_string.html#bpy-types-functionnodevaluetostring"),
("bpy.types.geometrynodeblurattribute*", "modeling/geometry_nodes/attribute/blur_attribute.html#bpy-types-geometrynodeblurattribute"),
("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/operations/curve_to_points.html#bpy-types-geometrynodecurvetopoints"),
("bpy.types.geometrynodeedgesofcorner*", "modeling/geometry_nodes/mesh/topology/edges_of_corner.html#bpy-types-geometrynodeedgesofcorner"),
("bpy.types.geometrynodeedgesofvertex*", "modeling/geometry_nodes/mesh/topology/edges_of_vertex.html#bpy-types-geometrynodeedgesofvertex"),
@ -2027,7 +2027,6 @@ url_manual_mapping = (
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
("bpy.ops.mball.delete_metaelems*", "modeling/metas/editing.html#bpy-ops-mball-delete-metaelems"),
("bpy.ops.mball.reveal_metaelems*", "modeling/metas/properties.html#bpy-ops-mball-reveal-metaelems"),
("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"),
("bpy.ops.mesh.vert_connect_path*", "modeling/meshes/editing/vertex/connect_vertex_path.html#bpy-ops-mesh-vert-connect-path"),
@ -2083,7 +2082,6 @@ url_manual_mapping = (
("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/operations/bounding_box.html#bpy-types-geometrynodeboundbox"),
("bpy.types.geometrynodecurvearc*", "modeling/geometry_nodes/curve/primitives/arc.html#bpy-types-geometrynodecurvearc"),
("bpy.types.geometrynodedualmesh*", "modeling/geometry_nodes/mesh/operations/dual_mesh.html#bpy-types-geometrynodedualmesh"),
("bpy.types.geometrynodematerial*", "-1"),
("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh/primitives/cone.html#bpy-types-geometrynodemeshcone"),
("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh/primitives/cube.html#bpy-types-geometrynodemeshcube"),
("bpy.types.geometrynodemeshgrid*", "modeling/geometry_nodes/mesh/primitives/grid.html#bpy-types-geometrynodemeshgrid"),

View File

@ -3478,7 +3478,8 @@ def km_animation_channels(params):
# Selection.
*_template_items_select_actions(params, "anim.channels_select_all"),
("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
{"properties": [("extend", False)]}),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
{"properties": [("extend", True)]}),
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "ctrl": True},
@ -5627,6 +5628,7 @@ def km_curves(params):
("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None),
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
*_template_items_select_actions(params, "curves.select_all"),
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
])
return keymap

View File

@ -35,19 +35,10 @@ def draw_node_group_add_menu(context, layout):
if node_tree:
from nodeitems_builtins import node_tree_group_type
def contains_group(nodetree, group):
if nodetree == group:
return True
for node in nodetree.nodes:
if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
if contains_group(node.node_tree, group):
return True
return False
groups = [
group for group in context.blend_data.node_groups
if (group.bl_idname == node_tree.bl_idname and
not contains_group(group, node_tree) and
not group.contains_tree(node_tree) and
not group.name.startswith('.'))
]
if groups:

View File

@ -2329,6 +2329,9 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_override_templates"},
("blender/blender/issues/73318",
"Milestone 4")),
({"property": "use_new_volume_nodes"},
("blender/blender/issues/103248",
"#103248")),
),
)

View File

@ -2052,6 +2052,7 @@ class VIEW3D_MT_select_edit_curves(Menu):
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
layout.operator("curves.select_random", text="Random")
layout.operator("curves.select_end", text="Endpoints")
layout.operator("curves.select_linked", text="Linked")
class VIEW3D_MT_select_sculpt_curves(Menu):

View File

@ -76,21 +76,11 @@ def node_group_items(context):
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
def contains_group(nodetree, group):
if nodetree == group:
return True
else:
for node in nodetree.nodes:
if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
if contains_group(node.node_tree, group):
return True
return False
for group in context.blend_data.node_groups:
if group.bl_idname != ntree.bl_idname:
continue
# filter out recursive groups
if contains_group(group, ntree):
if group.contains_tree(ntree):
continue
# filter out hidden nodetrees
if group.name.startswith('.'):

View File

@ -170,7 +170,6 @@ void BKE_mesh_vert_edge_vert_map_create(
*/
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
int totedge,
const struct MPoly *mpoly,
int totpoly,
@ -183,7 +182,6 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
*/
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
int totedge,
const struct MPoly *mpoly,
int totpoly,
@ -317,8 +315,7 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(float (*vert_positions)[3],
* starting at 1 (0 being used as 'invalid' flag).
* Note it's callers's responsibility to MEM_freeN returned array.
*/
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
int totedge,
int *BKE_mesh_calc_smoothgroups(int totedge,
const struct MPoly *mpoly,
int totpoly,
const struct MLoop *mloop,

View File

@ -504,7 +504,13 @@ struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node);
void ntreeFreeLocalTree(struct bNodeTree *ntree);
struct bNode *ntreeFindType(struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
/**
* Check recursively if a node tree contains another.
*/
bool ntreeContainsTree(const struct bNodeTree *tree_to_search_in,
const struct bNodeTree *tree_to_search_for);
void ntreeUpdateAllNew(struct Main *main);
void ntreeUpdateAllUsers(struct Main *main, struct ID *id);

View File

@ -2289,26 +2289,12 @@ bool CustomData_merge(const CustomData *source,
return changed;
}
static bool attribute_stored_in_bmesh_flag(const StringRef name)
{
return ELEM(name,
"position",
".hide_vert",
".hide_edge",
".hide_poly",
".select_vert",
".select_edge",
".select_poly",
"material_index",
"sharp_edge");
}
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
const eCustomDataMask mask)
{
Vector<CustomDataLayer> dst_layers;
for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) {
if (attribute_stored_in_bmesh_flag(layer.name)) {
if (BM_attribute_stored_in_bmesh_builtin(layer.name)) {
continue;
}
if (!(mask & CD_TYPE_AS_MASK(layer.type))) {

View File

@ -1261,7 +1261,9 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
found = true;
break;
}
if ((gpf->next) && (gpf->next->framenum > cframe)) {
/* If this is the last frame or the next frame is at a later time, we found the right
* frame. */
if (!(gpf->next) || (gpf->next->framenum > cframe)) {
found = true;
break;
}

View File

@ -15,6 +15,7 @@
#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_function_ref.hh"
#include "BLI_math.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@ -385,7 +386,6 @@ void BKE_mesh_vert_edge_vert_map_create(
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge * /*medge*/,
const int totedge,
const MPoly *mpoly,
const int totpoly,
@ -438,7 +438,6 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge * /*medge*/,
const int totedge,
const MPoly *mpoly,
const int totpoly,
@ -645,27 +644,19 @@ Vector<Vector<int>> build_edge_to_loop_map_resizable(const Span<MLoop> loops, co
/**
* Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
using MeshRemap_CheckIslandBoundary = bool (*)(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const int edge_index,
const bool *sharp_edges,
const int edge_user_count,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
void *user_data);
using MeshRemap_CheckIslandBoundary =
blender::FunctionRef<bool(int poly_index,
int loop_index,
int edge_index,
int edge_user_count,
const MeshElemMap &edge_poly_map_elem)>;
static void poly_edge_loop_islands_calc(const MEdge *medge,
const int totedge,
const MPoly *mpoly,
const int totpoly,
const MLoop *mloop,
const int totloop,
const bool *sharp_edges,
static void poly_edge_loop_islands_calc(const int totedge,
const blender::Span<MPoly> polys,
const blender::Span<MLoop> loops,
MeshElemMap *edge_poly_map,
const bool use_bitflags,
MeshRemap_CheckIslandBoundary edge_boundary_check,
void *edge_boundary_check_data,
int **r_poly_groups,
int *r_totgroup,
BLI_bitmap **r_edge_borders,
@ -689,7 +680,7 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
/* map vars */
int *edge_poly_mem = nullptr;
if (totpoly == 0) {
if (polys.size() == 0) {
*r_totgroup = 0;
*r_poly_groups = nullptr;
if (r_edge_borders) {
@ -705,12 +696,17 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
}
if (!edge_poly_map) {
BKE_mesh_edge_poly_map_create(
&edge_poly_map, &edge_poly_mem, medge, totedge, mpoly, totpoly, mloop, totloop);
BKE_mesh_edge_poly_map_create(&edge_poly_map,
&edge_poly_mem,
totedge,
polys.data(),
int(polys.size()),
loops.data(),
int(loops.size()));
}
poly_groups = static_cast<int *>(MEM_callocN(sizeof(int) * size_t(totpoly), __func__));
poly_stack = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(totpoly), __func__));
poly_groups = static_cast<int *>(MEM_callocN(sizeof(int) * size_t(polys.size()), __func__));
poly_stack = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(polys.size()), __func__));
while (true) {
int poly;
@ -718,13 +714,13 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
int poly_group_id;
int ps_curr_idx = 0, ps_end_idx = 0; /* stack indices */
for (poly = poly_prev; poly < totpoly; poly++) {
for (poly = poly_prev; poly < int(polys.size()); poly++) {
if (poly_groups[poly] == 0) {
break;
}
}
if (poly == totpoly) {
if (poly == int(polys.size())) {
/* all done */
break;
}
@ -738,23 +734,16 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
poly_stack[ps_end_idx++] = poly;
while (ps_curr_idx != ps_end_idx) {
const MPoly *mp;
const MLoop *ml;
int j;
poly = poly_stack[ps_curr_idx++];
BLI_assert(poly_groups[poly] == poly_group_id);
mp = &mpoly[poly];
for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) {
for (const int64_t loop : blender::IndexRange(polys[poly].loopstart, polys[poly].totloop)) {
const int edge = int(loops[loop].e);
/* loop over poly users */
const int me_idx = int(ml->e);
const MEdge *me = &medge[me_idx];
const MeshElemMap *map_ele = &edge_poly_map[me_idx];
const int *p = map_ele->indices;
int i = map_ele->count;
if (!edge_boundary_check(
mp, ml, me, me_idx, sharp_edges, i, mpoly, map_ele, edge_boundary_check_data)) {
const MeshElemMap &map_ele = edge_poly_map[edge];
const int *p = map_ele.indices;
int i = map_ele.count;
if (!edge_boundary_check(poly, int(loop), edge, i, map_ele)) {
for (; i--; p++) {
/* if we meet other non initialized its a bug */
BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
@ -766,8 +755,8 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
}
}
else {
if (edge_borders && !BLI_BITMAP_TEST(edge_borders, me_idx)) {
BLI_BITMAP_ENABLE(edge_borders, me_idx);
if (edge_borders && !BLI_BITMAP_TEST(edge_borders, edge)) {
BLI_BITMAP_ENABLE(edge_borders, edge);
num_edgeborders++;
}
if (use_bitflags) {
@ -828,7 +817,7 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
}
if (UNLIKELY(group_id_overflow)) {
int i = totpoly, *gid = poly_groups;
int i = int(polys.size()), *gid = poly_groups;
for (; i--; gid++) {
if (*gid == poly_group_id_overflowed) {
*gid = 0;
@ -852,31 +841,7 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
}
}
static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
const MLoop * /*ml*/,
const MEdge * /*me*/,
const int edge_index,
const bool *sharp_edges,
const int edge_user_count,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
void * /*user_data*/)
{
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
if ((mp->flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) &&
(edge_user_count == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
&mpoly_array[edge_poly_map->indices[1]] :
&mpoly_array[edge_poly_map->indices[0]];
return (mp_other->flag & ME_SMOOTH) == 0;
}
return true;
}
int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
const int totedge,
int *BKE_mesh_calc_smoothgroups(const int totedge,
const MPoly *mpoly,
const int totpoly,
const MLoop *mloop,
@ -887,17 +852,30 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
{
int *poly_groups = nullptr;
poly_edge_loop_islands_calc(medge,
totedge,
mpoly,
totpoly,
mloop,
totloop,
sharp_edges,
auto poly_is_island_boundary_smooth = [&](const int poly_index,
const int /*loop_index*/,
const int edge_index,
const int edge_user_count,
const MeshElemMap &edge_poly_map_elem) {
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
if ((mpoly[poly_index].flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) &&
(edge_user_count == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ?
edge_poly_map_elem.indices[1] :
edge_poly_map_elem.indices[0];
return (mpoly[other_poly_index].flag & ME_SMOOTH) == 0;
}
return true;
};
poly_edge_loop_islands_calc(totedge,
{mpoly, totpoly},
{mloop, totloop},
nullptr,
use_bitflags,
poly_is_island_boundary_smooth_cb,
nullptr,
poly_is_island_boundary_smooth,
&poly_groups,
r_totgroup,
nullptr,
@ -1021,64 +999,6 @@ void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
sizeof(*innrcut->indices) * size_t(num_innercut_items));
}
/* TODO: I'm not sure edge seam flag is enough to define UV islands?
* Maybe we should also consider UV-maps values
* themselves (i.e. different UV-edges for a same mesh-edge => boundary edge too?).
* Would make things much more complex though,
* and each UVMap would then need its own mesh mapping, not sure we want that at all!
*/
struct MeshCheckIslandBoundaryUv {
const MLoop *loops;
const float (*luvs)[2];
const MeshElemMap *edge_loop_map;
};
static bool mesh_check_island_boundary_uv(const MPoly * /*mp*/,
const MLoop *ml,
const MEdge *me,
const int /*edge_index*/,
const bool * /*sharp_edges*/,
const int /*edge_user_count*/,
const MPoly * /*mpoly_array*/,
const MeshElemMap * /*edge_poly_map*/,
void *user_data)
{
if (user_data) {
const MeshCheckIslandBoundaryUv *data = static_cast<const MeshCheckIslandBoundaryUv *>(
user_data);
const MLoop *loops = data->loops;
const float(*luvs)[2] = data->luvs;
const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
const uint v1 = loops[edge_to_loops->indices[0]].v;
const uint v2 = loops[edge_to_loops->indices[1]].v;
const float *uvco_v1 = luvs[edge_to_loops->indices[0]];
const float *uvco_v2 = luvs[edge_to_loops->indices[1]];
for (int i = 2; i < edge_to_loops->count; i += 2) {
if (loops[edge_to_loops->indices[i]].v == v1) {
if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]]) ||
!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]])) {
return true;
}
}
else {
BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
UNUSED_VARS_NDEBUG(v2);
if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]]) ||
!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]])) {
return true;
}
}
}
return false;
}
/* Edge is UV boundary if tagged as seam. */
return (me->flag & ME_SEAM) != 0;
}
static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
const int totedge,
const MPoly *polys,
@ -1098,8 +1018,6 @@ static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
MeshElemMap *edge_loop_map;
int *edge_loop_mem;
MeshCheckIslandBoundaryUv edge_boundary_check_data;
int *poly_indices;
int *loop_indices;
int num_pidx, num_lidx;
@ -1120,27 +1038,62 @@ static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE);
BKE_mesh_edge_poly_map_create(
&edge_poly_map, &edge_poly_mem, edges, totedge, polys, totpoly, loops, totloop);
&edge_poly_map, &edge_poly_mem, totedge, polys, totpoly, loops, totloop);
if (luvs) {
BKE_mesh_edge_loop_map_create(
&edge_loop_map, &edge_loop_mem, edges, totedge, polys, totpoly, loops, totloop);
edge_boundary_check_data.loops = loops;
edge_boundary_check_data.luvs = luvs;
edge_boundary_check_data.edge_loop_map = edge_loop_map;
&edge_loop_map, &edge_loop_mem, totedge, polys, totpoly, loops, totloop);
}
poly_edge_loop_islands_calc(edges,
totedge,
polys,
totpoly,
loops,
totloop,
nullptr,
/* TODO: I'm not sure edge seam flag is enough to define UV islands?
* Maybe we should also consider UV-maps values
* themselves (i.e. different UV-edges for a same mesh-edge => boundary edge too?).
* Would make things much more complex though,
* and each UVMap would then need its own mesh mapping, not sure we want that at all!
*/
auto mesh_check_island_boundary_uv = [&](const int /*poly_index*/,
const int loop_index,
const int edge_index,
const int /*edge_user_count*/,
const MeshElemMap & /*edge_poly_map_elem*/) -> bool {
if (luvs) {
const MeshElemMap &edge_to_loops = edge_loop_map[loops[loop_index].e];
BLI_assert(edge_to_loops.count >= 2 && (edge_to_loops.count % 2) == 0);
const uint v1 = loops[edge_to_loops.indices[0]].v;
const uint v2 = loops[edge_to_loops.indices[1]].v;
const float *uvco_v1 = luvs[edge_to_loops.indices[0]];
const float *uvco_v2 = luvs[edge_to_loops.indices[1]];
for (int i = 2; i < edge_to_loops.count; i += 2) {
if (loops[edge_to_loops.indices[i]].v == v1) {
if (!equals_v2v2(uvco_v1, luvs[edge_to_loops.indices[i]]) ||
!equals_v2v2(uvco_v2, luvs[edge_to_loops.indices[i + 1]])) {
return true;
}
}
else {
BLI_assert(loops[edge_to_loops.indices[i]].v == v2);
UNUSED_VARS_NDEBUG(v2);
if (!equals_v2v2(uvco_v2, luvs[edge_to_loops.indices[i]]) ||
!equals_v2v2(uvco_v1, luvs[edge_to_loops.indices[i + 1]])) {
return true;
}
}
}
return false;
}
/* Edge is UV boundary if tagged as seam. */
return (edges[edge_index].flag & ME_SEAM) != 0;
};
poly_edge_loop_islands_calc(totedge,
{polys, totpoly},
{loops, totloop},
edge_poly_map,
false,
mesh_check_island_boundary_uv,
luvs ? &edge_boundary_check_data : nullptr,
&poly_groups,
&num_poly_groups,
&edge_borders,

View File

@ -1424,7 +1424,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
/* Needed for islands (or plain mesh) to AStar graph conversion. */
BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src,
&edge_to_poly_map_src_buff,
edges_src,
num_edges_src,
polys_src,
num_polys_src,

View File

@ -3457,21 +3457,41 @@ bNode *ntreeFindType(bNodeTree *ntree, int type)
return nullptr;
}
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
static bool ntree_contains_tree_exec(const bNodeTree *tree_to_search_in,
const bNodeTree *tree_to_search_for,
Set<const bNodeTree *> &already_passed)
{
if (ntree == lookup) {
if (tree_to_search_in == tree_to_search_for) {
return true;
}
for (const bNode *node : ntree->all_nodes()) {
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
if (ntreeHasTree((bNodeTree *)node->id, lookup)) {
return true;
}
tree_to_search_in->ensure_topology_cache();
for (const bNode *node_group : tree_to_search_in->group_nodes()) {
const bNodeTree *sub_tree_search_in = reinterpret_cast<const bNodeTree *>(node_group->id);
if (!sub_tree_search_in) {
continue;
}
if (!already_passed.add(sub_tree_search_in)) {
continue;
}
if (ntree_contains_tree_exec(sub_tree_search_in, tree_to_search_for, already_passed)) {
return true;
}
}
return false;
}
bool ntreeContainsTree(const bNodeTree *tree_to_search_in, const bNodeTree *tree_to_search_for)
{
if (tree_to_search_in == tree_to_search_for) {
return true;
}
Set<const bNodeTree *> already_passed;
return ntree_contains_tree_exec(tree_to_search_in, tree_to_search_for, already_passed);
}
bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to)
{
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {

View File

@ -133,6 +133,20 @@ static char bm_face_flag_to_mflag(const BMFace *f)
return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0);
}
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
{
return ELEM(name,
"position",
".hide_vert",
".hide_edge",
".hide_poly",
".select_vert",
".select_edge",
".select_poly",
"material_index",
"sharp_edge");
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
static BMFace *bm_face_create_from_mpoly(BMesh &bm,
Span<MLoop> loops,

View File

@ -9,6 +9,16 @@
#include "bmesh.h"
#ifdef __cplusplus
# include "BLI_string_ref.hh"
/**
* \return Whether attributes with the given name are stored in special flags or fields in BMesh
* rather than in the regular custom data blocks.
*/
bool BM_attribute_stored_in_bmesh_builtin(const blender::StringRef name);
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -3499,7 +3499,8 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
return OPERATOR_FINISHED;
return WM_operator_flag_only_pass_through_on_press(OPERATOR_FINISHED | OPERATOR_PASS_THROUGH,
event);
}
static void ANIM_OT_channels_click(wmOperatorType *ot)

View File

@ -157,6 +157,19 @@ bool curves_poll(bContext *C)
return curves_poll_impl(C, false, false, false);
}
static bool editable_curves_point_domain_poll(bContext *C)
{
if (!curves::editable_curves_poll(C)) {
return false;
}
const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
return false;
}
return true;
}
using bke::CurvesGeometry;
namespace convert_to_particle_system {
@ -931,19 +944,6 @@ static void CURVES_OT_select_random(wmOperatorType *ot)
1.0f);
}
static bool select_end_poll(bContext *C)
{
if (!curves::editable_curves_poll(C)) {
return false;
}
const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
return false;
}
return true;
}
static int select_end_exec(bContext *C, wmOperator *op)
{
VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
@ -952,7 +952,7 @@ static int select_end_exec(bContext *C, wmOperator *op)
for (Curves *curves_id : unique_curves) {
CurvesGeometry &curves = curves_id->geometry.wrap();
select_ends(curves, eAttrDomain(curves_id->selection_domain), amount, end_points);
select_ends(curves, amount, end_points);
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */
@ -970,7 +970,7 @@ static void CURVES_OT_select_end(wmOperatorType *ot)
ot->description = "Select end points of curves";
ot->exec = select_end_exec;
ot->poll = select_end_poll;
ot->poll = editable_curves_point_domain_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -983,6 +983,33 @@ static void CURVES_OT_select_end(wmOperatorType *ot)
ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
}
static int select_linked_exec(bContext *C, wmOperator * /*op*/)
{
VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
for (Curves *curves_id : unique_curves) {
CurvesGeometry &curves = curves_id->geometry.wrap();
select_linked(curves);
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
return OPERATOR_FINISHED;
}
static void CURVES_OT_select_linked(wmOperatorType *ot)
{
ot->name = "Select Linked";
ot->idname = __func__;
ot->description = "Select all points in curves with any point selection";
ot->exec = select_linked_exec;
ot->poll = editable_curves_point_domain_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
namespace surface_set {
static bool surface_set_poll(bContext *C)
@ -1078,6 +1105,7 @@ void ED_operatortypes_curves()
WM_operatortype_append(CURVES_OT_select_all);
WM_operatortype_append(CURVES_OT_select_random);
WM_operatortype_append(CURVES_OT_select_end);
WM_operatortype_append(CURVES_OT_select_linked);
WM_operatortype_append(CURVES_OT_surface_set);
}

View File

@ -6,6 +6,7 @@
#include "BLI_array_utils.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_lasso_2d.h"
#include "BLI_rand.hh"
#include "BLI_rect.h"
@ -164,6 +165,21 @@ bool has_anything_selected(const bke::CurvesGeometry &curves)
return !selection || contains(selection, true);
}
bool has_anything_selected(const GSpan selection)
{
if (selection.type().is<bool>()) {
return selection.typed<bool>().contains(true);
}
else if (selection.type().is<float>()) {
for (const float elem : selection.typed<float>()) {
if (elem > 0.0f) {
return true;
}
}
}
return false;
}
static void invert_selection(MutableSpan<float> selection)
{
threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
@ -203,14 +219,12 @@ void select_all(bke::CurvesGeometry &curves, const eAttrDomain selection_domain,
}
}
void select_ends(bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
int amount,
bool end_points)
void select_ends(bke::CurvesGeometry &curves, int amount, bool end_points)
{
const bool was_anything_selected = has_anything_selected(curves);
const OffsetIndices points_by_curve = curves.points_by_curve();
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
if (!was_anything_selected) {
fill_selection_true(selection.span);
}
@ -223,7 +237,6 @@ void select_ends(bke::CurvesGeometry &curves,
MutableSpan<T> selection_typed = selection.span.typed<T>();
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
const OffsetIndices points_by_curve = curves.points_by_curve();
if (end_points) {
selection_typed.slice(points_by_curve[curve_i].drop_back(amount)).fill(T(0));
}
@ -237,6 +250,23 @@ void select_ends(bke::CurvesGeometry &curves,
selection.finish();
}
void select_linked(bke::CurvesGeometry &curves)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
GMutableSpan selection_curve = selection.span.slice(points_by_curve[curve_i]);
if (has_anything_selected(selection_curve)) {
fill_selection_true(selection_curve);
}
}
});
selection.finish();
}
void select_random(bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
uint32_t random_seed,
@ -397,7 +427,7 @@ bool select_pick(const ViewContext &vc,
bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
const SelectPick_Params &params,
const int2 mval)
const int2 coord)
{
FindClosestPointData closest_point;
bool found = find_closest_point_to_screen_co(*vc.depsgraph,
@ -405,7 +435,7 @@ bool select_pick(const ViewContext &vc,
vc.rv3d,
*vc.obact,
curves,
float2(mval),
float2(coord),
ED_view3d_select_dist_px(),
closest_point);
@ -446,8 +476,64 @@ bool select_box(const ViewContext &vc,
const rcti &rect,
const eSelectOp sel_op)
{
rctf rectf;
BLI_rctf_rcti_copy(&rectf, &rect);
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
bool changed = false;
if (sel_op == SEL_OP_SET) {
fill_selection_false(selection.span);
changed = true;
}
float4x4 projection;
ED_view3d_ob_project_mat_get(vc.rv3d, vc.obact, projection.ptr());
const bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_curves_deformation(*vc.depsgraph, *vc.obact);
const OffsetIndices points_by_curve = curves.points_by_curve();
if (selection_domain == ATTR_DOMAIN_POINT) {
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange point_range) {
for (const int point_i : point_range) {
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (BLI_rcti_isect_pt_v(&rect, int2(pos_proj))) {
apply_selection_operation_at_index(selection.span, point_i, sel_op);
changed = true;
}
}
});
}
else if (selection_domain == ATTR_DOMAIN_CURVE) {
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
for (const int point_i : points_by_curve[curve_i]) {
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (BLI_rcti_isect_pt_v(&rect, int2(pos_proj))) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break;
}
}
}
});
}
selection.finish();
return changed;
}
bool select_lasso(const ViewContext &vc,
bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
const Span<int2> coords,
const eSelectOp sel_op)
{
rcti bbox;
const int(*coord_array)[2] = reinterpret_cast<const int(*)[2]>(coords.data());
BLI_lasso_boundbox(&bbox, coord_array, coords.size());
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
@ -470,7 +556,10 @@ bool select_box(const ViewContext &vc,
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (BLI_rctf_isect_pt_v(&rectf, pos_proj)) {
/* Check the lasso bounding box first as an optimization. */
if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) &&
BLI_lasso_is_point_inside(
coord_array, coords.size(), int(pos_proj.x), int(pos_proj.y), IS_CLIPPED)) {
apply_selection_operation_at_index(selection.span, point_i, sel_op);
changed = true;
}
@ -484,7 +573,67 @@ bool select_box(const ViewContext &vc,
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (BLI_rctf_isect_pt_v(&rectf, pos_proj)) {
/* Check the lasso bounding box first as an optimization. */
if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) &&
BLI_lasso_is_point_inside(
coord_array, coords.size(), int(pos_proj.x), int(pos_proj.y), IS_CLIPPED)) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break;
}
}
}
});
}
selection.finish();
return changed;
}
bool select_circle(const ViewContext &vc,
bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
const int2 coord,
const float radius,
const eSelectOp sel_op)
{
const float radius_sq = pow2f(radius);
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
bool changed = false;
if (sel_op == SEL_OP_SET) {
fill_selection_false(selection.span);
changed = true;
}
float4x4 projection;
ED_view3d_ob_project_mat_get(vc.rv3d, vc.obact, projection.ptr());
const bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_curves_deformation(*vc.depsgraph, *vc.obact);
const OffsetIndices points_by_curve = curves.points_by_curve();
if (selection_domain == ATTR_DOMAIN_POINT) {
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange point_range) {
for (const int point_i : point_range) {
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (math::distance_squared(pos_proj, float2(coord)) <= radius_sq) {
apply_selection_operation_at_index(selection.span, point_i, sel_op);
changed = true;
}
}
});
}
else if (selection_domain == ATTR_DOMAIN_CURVE) {
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
for (const int point_i : points_by_curve[curve_i]) {
float2 pos_proj;
ED_view3d_project_float_v2_m4(
vc.region, deformation.positions[point_i], pos_proj, projection.ptr());
if (math::distance_squared(pos_proj, float2(coord)) <= radius_sq) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break;

View File

@ -3327,6 +3327,14 @@ void ED_gpencil_layer_merge(bGPdata *gpd,
gpf_dst->key_type = gpf_src->key_type;
BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
}
/* Copy current source frame to further frames
* that are keyframes in destination layer and not in source layer
* to keep the image equals. */
if (gpf_dst->next && (!gpf_src->next || (gpf_dst->next->framenum < gpf_src->next->framenum))) {
gpf_dst = gpf_dst->next;
BKE_gpencil_layer_frame_get(gpl_src, gpf_dst->framenum, GP_GETFRAME_ADD_COPY);
}
}
/* Read all frames from merge layer and add strokes. */

View File

@ -89,6 +89,11 @@ void fill_selection_true(GMutableSpan span);
*/
bool has_anything_selected(const bke::CurvesGeometry &curves);
/**
* Return true if any element in the span is selected, on either domain with either type.
*/
bool has_anything_selected(GSpan selection);
/**
* Find curves that have any point selected (a selection factor greater than zero),
* or curves that have their own selection factor greater than zero.
@ -123,10 +128,12 @@ void select_all(bke::CurvesGeometry &curves, const eAttrDomain selection_domain,
* \param amount: The amount of points to select from the front or back.
* \param end_points: If true, select the last point(s), if false, select the first point(s).
*/
void select_ends(bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
int amount,
bool end_points);
void select_ends(bke::CurvesGeometry &curves, int amount, bool end_points);
/**
* Select the points of all curves that have at least one point selected.
*/
void select_linked(bke::CurvesGeometry &curves);
/**
* Select random points or curves.
@ -141,13 +148,13 @@ void select_random(bke::CurvesGeometry &curves,
float probability);
/**
* Select point or curve under the cursor.
* Select point or curve at a (screen-space) point.
*/
bool select_pick(const ViewContext &vc,
bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
const SelectPick_Params &params,
const int2 mval);
const int2 coord);
/**
* Select points or curves in a (screen-space) rectangle.
@ -157,6 +164,25 @@ bool select_box(const ViewContext &vc,
const eAttrDomain selection_domain,
const rcti &rect,
const eSelectOp sel_op);
/**
* Select points or curves in a (screen-space) poly shape.
*/
bool select_lasso(const ViewContext &vc,
bke::CurvesGeometry &curves,
eAttrDomain selection_domain,
Span<int2> coords,
eSelectOp sel_op);
/**
* Select points or curves in a (screen-space) circle.
*/
bool select_circle(const ViewContext &vc,
bke::CurvesGeometry &curves,
eAttrDomain selection_domain,
int2 coord,
float radius,
eSelectOp sel_op);
/** \} */
} // namespace blender::ed::curves

View File

@ -19,7 +19,13 @@ struct bContext;
void ED_sequencer_select_sequence_single(struct Scene *scene,
struct Sequence *seq,
bool deselect_all);
void ED_sequencer_deselect_all(struct Scene *scene);
/**
* Iterates over a scene's sequences and deselects all of them.
*
* \param scene: scene containing sequences to be deselected.
* \return true if any sequences were deselected; false otherwise.
*/
bool ED_sequencer_deselect_all(struct Scene *scene);
bool ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene *scene);

View File

@ -28,6 +28,8 @@
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BLI_index_range.hh"
#include "DEG_depsgraph.h"
#include "WM_api.h"
@ -42,6 +44,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
using blender::IndexRange;
void SCULPT_dynamic_topology_triangulate(BMesh *bm)
{
if (bm->totloop != bm->totface * 3) {
@ -281,8 +285,8 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
uiLayout *layout = UI_popup_menu_layout(pup);
if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
const char *msg_error = TIP_("Vertex Data Detected!");
const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
const char *msg_error = TIP_("Attribute Data Detected");
const char *msg = TIP_("Dyntopo will not preserve colors, UVs, or other attributes");
uiItemL(layout, msg_error, ICON_INFO);
uiItemL(layout, msg, ICON_NONE);
uiItemS(layout);
@ -305,6 +309,39 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
return OPERATOR_INTERFACE;
}
static bool dyntopo_supports_customdata_layers(const blender::Span<CustomDataLayer> layers,
int totelem)
{
for (const CustomDataLayer &layer : layers) {
if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) {
if (layer.name[0] == '\0') {
return false;
}
if (STREQ(layer.name, ".sculpt_face_sets") && totelem > 0) {
int *fsets = static_cast<int *>(layer.data);
int fset = fsets[0];
/* Check if only one face set exists. */
for (int i : IndexRange(totelem)) {
if (fsets[i] != fset) {
return false;
}
}
return true;
}
/* Some data is stored as generic attributes on #Mesh but in flags or field on #BMesh. */
return BM_attribute_stored_in_bmesh_builtin(layer.name);
}
/* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */
return ELEM(layer.type, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX);
}
return true;
}
enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
{
Mesh *me = static_cast<Mesh *>(ob->data);
@ -315,18 +352,17 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
BLI_assert(ss->bm == nullptr);
UNUSED_VARS_NDEBUG(ss);
for (int i = 0; i < CD_NUMTYPES; i++) {
if (!ELEM(i, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
if (CustomData_has_layer(&me->vdata, i)) {
flag |= DYNTOPO_WARN_VDATA;
}
if (CustomData_has_layer(&me->edata, i)) {
flag |= DYNTOPO_WARN_EDATA;
}
if (CustomData_has_layer(&me->ldata, i)) {
flag |= DYNTOPO_WARN_LDATA;
}
}
if (!dyntopo_supports_customdata_layers({me->vdata.layers, me->vdata.totlayer}, me->totvert)) {
flag |= DYNTOPO_WARN_VDATA;
}
if (!dyntopo_supports_customdata_layers({me->edata.layers, me->edata.totlayer}, me->totedge)) {
flag |= DYNTOPO_WARN_EDATA;
}
if (!dyntopo_supports_customdata_layers({me->pdata.layers, me->pdata.totlayer}, me->totpoly)) {
flag |= DYNTOPO_WARN_LDATA;
}
if (!dyntopo_supports_customdata_layers({me->ldata.layers, me->ldata.totlayer}, me->totloop)) {
flag |= DYNTOPO_WARN_LDATA;
}
{

View File

@ -548,7 +548,6 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, const FaceSetsFloodFill
if (!ss->epmap) {
BKE_mesh_edge_poly_map_create(&ss->epmap,
&ss->epmap_mem,
edges.data(),
edges.size(),
polys.data(),
polys.size(),

View File

@ -95,14 +95,8 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
BLI_bitmap *edge_tag = BLI_BITMAP_NEW(totedge, "edge tag");
if (!ss->epmap) {
BKE_mesh_edge_poly_map_create(&ss->epmap,
&ss->epmap_mem,
edges,
mesh->totedge,
polys,
mesh->totpoly,
loops,
mesh->totloop);
BKE_mesh_edge_poly_map_create(
&ss->epmap, &ss->epmap_mem, mesh->totedge, polys, mesh->totpoly, loops, mesh->totloop);
}
if (!ss->vemap) {
BKE_mesh_vert_edge_map_create(&ss->vemap, &ss->vemap_mem, edges, mesh->totvert, mesh->totedge);

View File

@ -1456,6 +1456,7 @@ static void std_node_socket_interface_draw(bContext * /*C*/, uiLayout *layout, P
case SOCK_STRING:
case SOCK_OBJECT:
case SOCK_COLLECTION:
case SOCK_IMAGE:
case SOCK_TEXTURE:
case SOCK_MATERIAL: {
uiItemR(col, ptr, "default_value", DEFAULT_FLAGS, IFACE_("Default"), 0);

View File

@ -715,7 +715,7 @@ void ED_node_set_active(
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
/* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) {
if (ma->nodetree && ma->use_nodes && ntreeContainsTree(ma->nodetree, ntree)) {
GPU_material_free(&ma->gpumaterial);
/* Sync to active texpaint slot, otherwise we can end up painting on a different slot
@ -734,7 +734,7 @@ void ED_node_set_active(
}
LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) {
if (wo->nodetree && wo->use_nodes && ntreeContainsTree(wo->nodetree, ntree)) {
GPU_material_free(&wo->gpumaterial);
}
}

View File

@ -1094,24 +1094,6 @@ void NODE_OT_group_make(wmOperatorType *ot)
/** \name Group Insert Operator
* \{ */
static bool node_tree_contains_tree_recursive(const bNodeTree &ntree_to_search_in,
const bNodeTree &ntree_to_search_for)
{
if (&ntree_to_search_in == &ntree_to_search_for) {
return true;
}
ntree_to_search_in.ensure_topology_cache();
for (const bNode *node : ntree_to_search_in.group_nodes()) {
if (node->id) {
if (node_tree_contains_tree_recursive(*reinterpret_cast<bNodeTree *>(node->id),
ntree_to_search_for)) {
return true;
}
}
}
return false;
}
static int node_group_insert_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
@ -1133,7 +1115,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
if (!group->is_group() || group->id == nullptr) {
continue;
}
if (node_tree_contains_tree_recursive(*reinterpret_cast<bNodeTree *>(group->id), *ngroup)) {
if (ntreeContainsTree(reinterpret_cast<bNodeTree *>(group->id), ngroup)) {
BKE_reportf(
op->reports, RPT_WARNING, "Can not insert group '%s' in '%s'", group->name, gnode->name);
return OPERATOR_CANCELLED;

View File

@ -2492,17 +2492,22 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
/** \name Paste Operator
* \{ */
void ED_sequencer_deselect_all(Scene *scene)
bool ED_sequencer_deselect_all(Scene *scene)
{
Editing *ed = SEQ_editing_get(scene);
bool changed = false;
if (ed == NULL) {
return;
return changed;
}
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
seq->flag &= ~SEQ_ALLSEL;
if (seq->flag & SEQ_ALLSEL) {
seq->flag &= ~SEQ_ALLSEL;
changed = true;
}
}
return changed;
}
static void sequencer_paste_animation(bContext *C)

View File

@ -974,8 +974,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* Deselect everything */
if (deselect_all || (seq && (extend == false && deselect == false && toggle == false))) {
ED_sequencer_deselect_all(scene);
changed = true;
changed |= ED_sequencer_deselect_all(scene);
}
/* Nothing to select, but strips could be deselected. */

View File

@ -1303,6 +1303,7 @@ static bool view3d_lasso_select(bContext *C,
const int mcoords_len,
const eSelectOp sel_op)
{
using namespace blender;
Object *ob = CTX_data_active_object(C);
bool changed_multi = false;
@ -1362,6 +1363,23 @@ static bool view3d_lasso_select(bContext *C,
case OB_MBALL:
changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
break;
case OB_CURVES: {
Curves &curves_id = *static_cast<Curves *>(vc->obedit->data);
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
changed = ed::curves::select_lasso(
*vc,
curves,
eAttrDomain(curves_id.selection_domain),
Span<int2>(reinterpret_cast<const int2 *>(mcoords), mcoords_len),
sel_op);
if (changed) {
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, vc->obedit->data);
}
break;
}
default:
BLI_assert_msg(0, "lasso select on incorrect object type");
break;
@ -3550,8 +3568,7 @@ static bool do_mesh_box_select(ViewContext *vc,
}
if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
struct BoxSelectUserData_ForMeshEdge cb_data {
};
struct BoxSelectUserData_ForMeshEdge cb_data {};
cb_data.data = &data;
cb_data.esel = use_zbuf ? esel : nullptr;
cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
@ -3957,7 +3974,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
break;
case OB_CURVES: {
Curves &curves_id = *static_cast<Curves *>(vc.obact->data);
Curves &curves_id = *static_cast<Curves *>(vc.obedit->data);
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
changed = ed::curves::select_box(
vc, curves, eAttrDomain(curves_id.selection_domain), rect, sel_op);
@ -4701,6 +4718,7 @@ static bool obedit_circle_select(bContext *C,
const int mval[2],
float rad)
{
using namespace blender;
bool changed = false;
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
switch (vc->obedit->type) {
@ -4723,6 +4741,20 @@ static bool obedit_circle_select(bContext *C,
case OB_MBALL:
changed = mball_circle_select(vc, sel_op, mval, rad);
break;
case OB_CURVES: {
Curves &curves_id = *static_cast<Curves *>(vc->obedit->data);
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
changed = ed::curves::select_circle(
*vc, curves, eAttrDomain(curves_id.selection_domain), mval, rad, sel_op);
if (changed) {
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, vc->obedit->data);
}
break;
}
default:
BLI_assert(0);
break;

View File

@ -194,8 +194,7 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
{
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&export_mesh_->edata, CD_PROP_BOOL, "sharp_edge"));
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.data(),
mesh_edges_.size(),
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
mesh_polys_.data(),
mesh_polys_.size(),
mesh_loops_.data(),

View File

@ -653,7 +653,8 @@ typedef struct UserDef_Experimental {
char enable_eevee_next;
char use_sculpt_texture_paint;
char enable_workbench_next;
char _pad[7];
char use_new_volume_nodes;
char _pad[6];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;

View File

@ -1073,19 +1073,19 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
};
static const EnumPropertyItem prop_align_y_items[] = {
{CU_ALIGN_Y_TOP, "TOP", ICON_ALIGN_TOP, "Top", "Align text to the top"},
{CU_ALIGN_Y_TOP_BASELINE,
"TOP_BASELINE",
ICON_ALIGN_TOP,
"Top Base-Line",
"Align to top but use the base-line of the text"},
{CU_ALIGN_Y_TOP, "TOP", ICON_ALIGN_TOP, "Top", "Align text to the top"},
{CU_ALIGN_Y_CENTER, "CENTER", ICON_ALIGN_MIDDLE, "Center", "Align text to the middle"},
{CU_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ALIGN_BOTTOM, "Bottom", "Align text to the bottom"},
"Top Baseline",
"Align text to the top line's baseline"},
{CU_ALIGN_Y_CENTER, "CENTER", ICON_ALIGN_MIDDLE, "Middle", "Align text to the middle"},
{CU_ALIGN_Y_BOTTOM_BASELINE,
"BOTTOM_BASELINE",
ICON_ALIGN_BOTTOM,
"Bottom Base-Line",
"Align text to the bottom but use the base-line of the text"},
"Bottom Baseline",
"Align text to the bottom line's baseline"},
{CU_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ALIGN_BOTTOM, "Bottom", "Align text to the bottom"},
{0, NULL, 0, NULL, NULL},
};
@ -1109,14 +1109,14 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "spacemode");
RNA_def_property_enum_items(prop, prop_align_items);
RNA_def_property_ui_text(
prop, "Text Horizontal Align", "Text horizontal align from the object center");
prop, "Horizontal Alignment", "Text horizontal alignment from the object center");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, prop_align_y_items);
RNA_def_property_ui_text(
prop, "Text Vertical Align", "Text vertical align from the object center");
prop, "Vertical Alignment", "Text vertical alignment from the object center");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "overflow", PROP_ENUM, PROP_NONE);

View File

@ -93,8 +93,7 @@ static void rna_Mesh_calc_smooth_groups(
*r_poly_group_len = mesh->totpoly;
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
&mesh->edata, CD_PROP_BOOL, "sharp_edge");
*r_poly_group = BKE_mesh_calc_smoothgroups(BKE_mesh_edges(mesh),
mesh->totedge,
*r_poly_group = BKE_mesh_calc_smoothgroups(mesh->totedge,
BKE_mesh_polys(mesh),
mesh->totpoly,
BKE_mesh_loops(mesh),

View File

@ -1435,6 +1435,11 @@ static void rna_NodeTree_active_output_set(PointerRNA *ptr, int value)
}
}
static bool rna_NodeTree_contains_tree(bNodeTree *tree, bNodeTree *sub_tree)
{
return ntreeContainsTree(tree, sub_tree);
}
static bNodeSocket *rna_NodeTree_inputs_new(
bNodeTree *ntree, Main *bmain, ReportList *reports, const char *type, const char *name)
{
@ -10706,16 +10711,16 @@ static void def_geo_string_to_curves(StructRNA *srna)
};
static const EnumPropertyItem rna_node_geometry_string_to_curves_align_y_items[] = {
{GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE,
"TOP_BASELINE",
ICON_ALIGN_TOP,
"Top Baseline",
"Align text to the top baseline"},
{GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP,
"TOP",
ICON_ALIGN_TOP,
"Top",
"Align text to the top"},
{GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE,
"TOP_BASELINE",
ICON_ALIGN_TOP,
"Top Baseline",
"Align text to the top line's baseline"},
{GEO_NODE_STRING_TO_CURVES_ALIGN_Y_MIDDLE,
"MIDDLE",
ICON_ALIGN_MIDDLE,
@ -10725,7 +10730,7 @@ static void def_geo_string_to_curves(StructRNA *srna)
"BOTTOM_BASELINE",
ICON_ALIGN_BOTTOM,
"Bottom Baseline",
"Align text to the bottom baseline"},
"Align text to the bottom line's baseline"},
{GEO_NODE_STRING_TO_CURVES_ALIGN_Y_BOTTOM,
"BOTTOM",
ICON_ALIGN_BOTTOM,
@ -10777,21 +10782,23 @@ static void def_geo_string_to_curves(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "overflow");
RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_overflow_items);
RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
RNA_def_property_ui_text(prop, "Overflow", "");
RNA_def_property_ui_text(prop, "Textbox Overflow", "Handle the text behavior when it doesn't fit in the text boxes");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_x");
RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_align_x_items);
RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT);
RNA_def_property_ui_text(prop, "Align X", "");
RNA_def_property_ui_text(
prop, "Horizontal Alignment", "Text horizontal alignment from the object center");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_align_y_items);
RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE);
RNA_def_property_ui_text(prop, "Align Y", "");
RNA_def_property_ui_text(
prop, "Vertical Alignment", "Text vertical alignment from the object center");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "pivot_mode", PROP_ENUM, PROP_NONE);
@ -12719,6 +12726,16 @@ static void rna_def_nodetree(BlenderRNA *brna)
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
func = RNA_def_function(srna, "contains_tree", "rna_NodeTree_contains_tree");
RNA_def_function_ui_description(
func,
"Check if the node tree contains another. Used to avoid creating recursive node groups");
parm = RNA_def_pointer(
func, "sub_tree", "NodeTree", "Node Tree", "Node tree for recursive check");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "contained", PROP_BOOLEAN, PROP_NONE);
RNA_def_function_return(func, parm);
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");

View File

@ -762,6 +762,13 @@ static const EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C
}
return items;
}
# else
static int rna_lang_enum_properties_get_no_international(PointerRNA *UNUSED(ptr))
{
/* This simply prevents warnings when accessing language
* (since the actual value wont be in the enum, unless already `DEFAULT`). */
return 0;
}
# endif
static IDProperty **rna_AddonPref_idprops(PointerRNA *ptr)
@ -4880,6 +4887,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_language_default_items);
# ifdef WITH_INTERNATIONAL
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf");
# else
RNA_def_property_enum_funcs(prop, "rna_lang_enum_properties_get_no_international", NULL, NULL);
# endif
RNA_def_property_ui_text(prop, "Language", "Language used for translation");
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
@ -6447,6 +6456,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"All Linked Data Direct",
"Forces all linked data to be considered as directly linked. Workaround for current "
"issues/limitations in BAT (Blender studio pipeline tool)");
prop = RNA_def_property(srna, "use_new_volume_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop, "New Volume Nodes", "Enables visibility of the new Volume nodes in the UI");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)

View File

@ -28,12 +28,14 @@ static void copy_data_based_on_map(const Span<T> src,
const Span<int> index_map,
MutableSpan<T> dst)
{
for (const int i_src : index_map.index_range()) {
const int i_dst = index_map[i_src];
if (i_dst != -1) {
dst[i_dst] = src[i_src];
threading::parallel_for(index_map.index_range(), 1024, [&](const IndexRange range) {
for (const int i_src : range) {
const int i_dst = index_map[i_src];
if (i_dst != -1) {
dst[i_dst] = src[i_src];
}
}
}
});
}
/**
@ -159,13 +161,15 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh,
const Span<MEdge> src_edges = src_mesh.edges();
MutableSpan<MEdge> dst_edges = dst_mesh.edges_for_write();
for (const int i_src : IndexRange(src_mesh.totedge)) {
const int i_dst = edge_map[i_src];
if (ELEM(i_dst, -1, -2)) {
continue;
threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange range) {
for (const int i_src : range) {
const int i_dst = edge_map[i_src];
if (ELEM(i_dst, -1, -2)) {
continue;
}
dst_edges[i_dst] = src_edges[i_src];
}
dst_edges[i_dst] = src_edges[i_src];
}
});
}
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
@ -178,18 +182,20 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
const Span<MEdge> src_edges = src_mesh.edges();
MutableSpan<MEdge> dst_edges = dst_mesh.edges_for_write();
for (const int i_src : IndexRange(src_mesh.totedge)) {
const int i_dst = edge_map[i_src];
if (i_dst == -1) {
continue;
}
const MEdge &e_src = src_edges[i_src];
MEdge &e_dst = dst_edges[i_dst];
threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange range) {
for (const int i_src : range) {
const int i_dst = edge_map[i_src];
if (i_dst == -1) {
continue;
}
const MEdge &e_src = src_edges[i_src];
MEdge &e_dst = dst_edges[i_dst];
e_dst = e_src;
e_dst.v1 = vertex_map[e_src.v1];
e_dst.v2 = vertex_map[e_src.v2];
}
e_dst = e_src;
e_dst.v1 = vertex_map[e_src.v1];
e_dst.v2 = vertex_map[e_src.v2];
}
});
}
/* Faces and edges changed but vertices are the same. */
@ -204,24 +210,26 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
for (const int i_dst : masked_poly_indices.index_range()) {
const int i_src = masked_poly_indices[i_dst];
threading::parallel_for(masked_poly_indices.index_range(), 512, [&](const IndexRange range) {
for (const int i_dst : range) {
const int i_src = masked_poly_indices[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = ml_src[i].v;
ml_dst[i].e = edge_map[ml_src[i].e];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = ml_src[i].v;
ml_dst[i].e = edge_map[ml_src[i].e];
}
}
}
});
}
/* Only faces changed. */
@ -235,24 +243,26 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
for (const int i_dst : masked_poly_indices.index_range()) {
const int i_src = masked_poly_indices[i_dst];
threading::parallel_for(masked_poly_indices.index_range(), 512, [&](const IndexRange range) {
for (const int i_dst : range) {
const int i_src = masked_poly_indices[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = ml_src[i].v;
ml_dst[i].e = ml_src[i].e;
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = ml_src[i].v;
ml_dst[i].e = ml_src[i].e;
}
}
}
});
}
static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
@ -267,24 +277,26 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
MutableSpan<MPoly> dst_polys = dst_mesh.polys_for_write();
MutableSpan<MLoop> dst_loops = dst_mesh.loops_for_write();
for (const int i_dst : masked_poly_indices.index_range()) {
const int i_src = masked_poly_indices[i_dst];
threading::parallel_for(masked_poly_indices.index_range(), 512, [&](const IndexRange range) {
for (const int i_dst : range) {
const int i_src = masked_poly_indices[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MPoly &mp_src = src_polys[i_src];
MPoly &mp_dst = dst_polys[i_dst];
const int i_ml_src = mp_src.loopstart;
const int i_ml_dst = new_loop_starts[i_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
const MLoop *ml_src = &src_loops[i_ml_src];
MLoop *ml_dst = &dst_loops[i_ml_dst];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = vertex_map[ml_src[i].v];
ml_dst[i].e = edge_map[ml_src[i].e];
mp_dst = mp_src;
mp_dst.loopstart = i_ml_dst;
for (int i : IndexRange(mp_src.totloop)) {
ml_dst[i].v = vertex_map[ml_src[i].v];
ml_dst[i].e = edge_map[ml_src[i].e];
}
}
}
});
}
static void delete_curves_selection(GeometrySet &geometry_set,
@ -574,16 +586,20 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
int *r_selected_polys_num,
int *r_selected_loops_num)
{
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polys_from_vertex_selection(mesh,
vertex_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
threading::parallel_invoke(
mesh.totedge > 1000,
[&]() {
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
},
[&]() {
compute_selected_polys_from_vertex_selection(mesh,
vertex_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
});
}
/**
@ -601,18 +617,24 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
int *r_selected_polys_num,
int *r_selected_loops_num)
{
compute_selected_verts_from_vertex_selection(
vertex_selection, r_vertex_map, r_selected_verts_num);
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polys_from_vertex_selection(mesh,
vertex_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
threading::parallel_invoke(
mesh.totedge > 1000,
[&]() {
compute_selected_verts_from_vertex_selection(
vertex_selection, r_vertex_map, r_selected_verts_num);
},
[&]() {
compute_selected_edges_from_vertex_selection(
mesh, vertex_selection, r_edge_map, r_selected_edges_num);
},
[&]() {
compute_selected_polys_from_vertex_selection(mesh,
vertex_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
});
}
/**
@ -629,14 +651,20 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
int *r_selected_polys_num,
int *r_selected_loops_num)
{
compute_selected_edges_from_edge_selection(
mesh, edge_selection, r_edge_map, r_selected_edges_num);
compute_selected_polys_from_edge_selection(mesh,
edge_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
threading::parallel_invoke(
mesh.totedge > 1000,
[&]() {
compute_selected_edges_from_edge_selection(
mesh, edge_selection, r_edge_map, r_selected_edges_num);
},
[&]() {
compute_selected_polys_from_edge_selection(mesh,
edge_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
});
}
/**
@ -654,15 +682,25 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
int *r_selected_polys_num,
int *r_selected_loops_num)
{
r_vertex_map.fill(-1);
compute_selected_verts_and_edges_from_edge_selection(
mesh, edge_selection, r_vertex_map, r_edge_map, r_selected_verts_num, r_selected_edges_num);
compute_selected_polys_from_edge_selection(mesh,
edge_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
threading::parallel_invoke(
mesh.totedge > 1000,
[&]() {
r_vertex_map.fill(-1);
compute_selected_verts_and_edges_from_edge_selection(mesh,
edge_selection,
r_vertex_map,
r_edge_map,
r_selected_verts_num,
r_selected_edges_num);
},
[&]() {
compute_selected_polys_from_edge_selection(mesh,
edge_selection,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
r_selected_loops_num);
});
}
/**

View File

@ -39,7 +39,6 @@ def get_gpu_device(args: None) -> List:
if device.type == device_type:
result.append({'type': device.type, 'name': device.name, 'index': index})
index += 1
break
return result

View File

@ -4,13 +4,15 @@
# ./blender.bin --background -noaudio --python tests/python/bl_rna_manual_reference.py
#
# 1) test_data() -- ensure the data we have is correct format
# 2) test_lookup_coverage() -- ensure that we have lookups for _every_ RNA path
# 2) test_lookup_coverage() -- ensure that we have lookups for _every_ RNA path and all patterns are used.
# 3) test_urls() -- ensure all the URL's are correct
# 4) test_language_coverage() -- ensure language lookup table is complete
#
import bpy
VERBOSE = False
def test_data():
import rna_manual_reference
@ -28,6 +30,21 @@ def test_data():
raise
def lookup_rna_url(rna_id, visit_indices):
"""
A local version of ``WM_OT_doc_view_manual._lookup_rna_url``
that tracks which matches are found.
"""
import rna_manual_reference
from fnmatch import fnmatchcase
rna_id = rna_id.lower()
for i, (pattern, url_suffix) in enumerate(rna_manual_reference.url_manual_mapping):
if fnmatchcase(rna_id, pattern):
visit_indices.add(i)
return rna_manual_reference.url_manual_prefix + url_suffix
return None
# a stripped down version of api_dump() in rna_info_dump.py
def test_lookup_coverage():
@ -51,14 +68,37 @@ def test_lookup_coverage():
set_group_all = set()
set_group_doc = set()
visit_indices = set()
print("")
print("----------------------------------")
print("RNA Patterns Unknown to the Manual")
unknown_rna_list = []
for rna_group, rna_id in rna_ids():
url = wm.WM_OT_doc_view_manual._lookup_rna_url(rna_id, verbose=False)
print(rna_id, "->", url)
# Correct but slower & doesn't track usage.
# url = wm.WM_OT_doc_view_manual._lookup_rna_url(rna_id, verbose=False)
url = lookup_rna_url(rna_id, visit_indices)
if VERBOSE:
print(rna_id, "->", url)
else:
print(rna_id)
set_group_all.add(rna_group)
if url is not None:
set_group_doc.add(rna_group)
print("")
print("---------------------------------------")
print("Unused RNA Patterns Known to the Manual")
import rna_manual_reference
for i, (pattern, url_suffix) in enumerate(rna_manual_reference.url_manual_mapping):
if i not in visit_indices:
print(pattern, url_suffix)
# finally report undocumented groups
print("")
print("---------------------")
@ -103,13 +143,16 @@ def test_urls():
if LOCAL_PREFIX:
for url in sorted(urls):
url_full = os.path.join(LOCAL_PREFIX, url.partition("#")[0])
print(" %s ... " % url_full, end="")
if os.path.exists(url_full):
print(color_green + "OK" + color_normal)
if VERBOSE:
print(" %s ... " % url_full, end="")
print(color_green + "OK" + color_normal)
else:
print(" %s ... " % url_full, end="")
print(color_red + "FAIL!" + color_normal)
urls_fail.append(url)
else:
elif False:
# URL lookups are too slow to be practical.
for url in sorted(urls):
url_full = prefix + url
print(" %s ... " % url_full, end="")
@ -120,6 +163,8 @@ def test_urls():
except urllib.error.HTTPError:
print(color_red + "FAIL!" + color_normal)
urls_fail.append(url)
else:
print("Skipping URL lookups, define LOCAL_PREFIX env variable, and point it to a manual build!")
if urls_fail:
urls_len = "%d" % len(urls_fail)