Grease Pencil: Set Layers' 'Use Lights' Default to False #104550
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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('.'):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¶ms,
|
||||
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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 ¶ms,
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue