Brush Assets: Add catalog option to asset pushing operator #118382

Merged
Hans Goudey merged 26 commits from HooglyBoogly/blender:brush-assets-save-catalog-option into brush-assets-project 2024-02-21 14:03:41 +01:00
75 changed files with 617 additions and 379 deletions
Showing only changes of commit 676cfb9af7 - Show all commits

View File

@ -279,5 +279,5 @@ StatementMacros:
MacroBlockBegin: "^OSL_CLOSURE_STRUCT_BEGIN$"
MacroBlockEnd: "^OSL_CLOSURE_STRUCT_END$"
# Ensure lew line at the end of source files.
# Ensure new line at the end of source files.
InsertNewlineAtEOF: True

View File

@ -8814,9 +8814,9 @@ class VIEW3D_PT_viewport_debug(Panel):
class BrushAssetShelf:
bl_space_type = "VIEW_3D"
bl_options = {'NO_ASSET_DRAG'}
bl_options = {'DEFAULT_VISIBLE', 'NO_ASSET_DRAG'}
bl_activate_operator = "BRUSH_OT_asset_select"
bl_default_preview_size = 40
bl_default_preview_size = 48
@classmethod
def poll(cls, context):

View File

@ -61,8 +61,9 @@ class VIEW3D_MT_brush_context_menu(Menu):
layout.operator("brush.asset_update", text="Update Asset")
layout.operator("brush.asset_revert", text="Revert to Asset")
if context.sculpt_object:
layout.operator("brush.reset", text="Reset to Defaults")
# TODO: does not behave in a useful way now, eventually improve or remove entirely.
# if context.sculpt_object:
# layout.operator("brush.reset", text="Reset to Defaults")
else:
layout.operator("brush.asset_save_as", text="Save As Asset...", icon='FILE_TICK')
layout.operator("brush.asset_delete", text="Delete")

View File

@ -12,6 +12,7 @@
#include <mutex>
#include "BLI_bit_span.hh"
#include "BLI_index_mask_fwd.hh"
#include "BLI_kdopbvh.h"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
@ -114,6 +115,13 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
BVHCacheType bvh_cache_type,
int tree_type);
/**
* Build a bvh tree from the triangles in the mesh that correspond to the faces in the given mask.
*/
void BKE_bvhtree_from_mesh_tris_init(const Mesh &mesh,
const blender::IndexMask &faces_mask,
BVHTreeFromMesh &r_data);
/**
* Frees data allocated by a call to `bvhtree_from_mesh_*`.
*/

View File

@ -109,6 +109,14 @@ struct IDTypeInfo {
*/
uint64_t id_filter;
/**
* Known types of ID dependencies.
*
* Used by #BKE_library_id_can_use_filter_id, together with additional runtime heuristics, to
* generate a filter value containing only ID types that given ID could be using.
*/
uint64_t dependencies_id_types;
/**
* Define the position of this data-block type in the virtual list of all data in a Main that is
* returned by `set_listbasepointers()`.
@ -337,6 +345,24 @@ bool BKE_idtype_idcode_append_is_reusable(short idcode);
*/
short BKE_idtype_idcode_from_name(const char *idtype_name);
/**
* Convert an \a idcode into an \a idtype_index (e.g. #ID_OB -> #INDEX_ID_OB).
*/
int BKE_idtype_idcode_to_index(short idcode);
/**
* Convert an \a idfilter into an \a idtype_index (e.g. #FILTER_ID_OB -> #INDEX_ID_OB).
*/
int BKE_idtype_idfilter_to_index(uint64_t idfilter);
/**
* Convert an \a idtype_index into an \a idcode (e.g. #INDEX_ID_OB -> #ID_OB).
*/
short BKE_idtype_index_to_idcode(int idtype_index);
/**
* Convert an \a idtype_index into an \a idfilter (e.g. #INDEX_ID_OB -> #FILTER_ID_OB).
*/
uint64_t BKE_idtype_index_to_idfilter(int idtype_index);
/**
* Convert an \a idcode into an \a idfilter (e.g. #ID_OB -> #FILTER_ID_OB).
*/
@ -344,16 +370,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(short idcode);
/**
* Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
*/
short BKE_idtype_idcode_from_idfilter(uint64_t idfilter);
/**
* Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
*/
int BKE_idtype_idcode_to_index(short idcode);
/**
* Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
*/
short BKE_idtype_idcode_from_index(int index);
short BKE_idtype_idfilter_to_idcode(uint64_t idfilter);
/**
* Return an ID code and steps the index forward 1.
@ -361,7 +378,7 @@ short BKE_idtype_idcode_from_index(int index);
* \param index: start as 0.
* \return the code, 0 when all codes have been returned.
*/
short BKE_idtype_idcode_iter_step(int *index);
short BKE_idtype_idcode_iter_step(int *idtype_index);
/* Some helpers/wrappers around callbacks defined in #IDTypeInfo, dealing e.g. with embedded IDs.
* XXX Ideally those would rather belong to #BKE_lib_id, but using callback function pointers makes

View File

@ -25,6 +25,7 @@
#include <array>
struct IDTypeInfo;
struct LibraryForeachIDData;
struct Main;
@ -299,7 +300,9 @@ bool BKE_library_id_can_use_idtype(ID *owner_id, short id_type_used);
/**
* Given the owner_id return the type of id_types it can use as a filter_id.
*/
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui);
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id,
const bool include_ui,
const IDTypeInfo *owner_id_type = nullptr);
/**
* Check whether given ID is used locally (i.e. by another non-linked ID).

View File

@ -290,6 +290,17 @@ inline int face_triangles_num(const int face_size)
return face_size - 2;
}
/**
* Return the range of triangles that belong to the given face.
*/
inline IndexRange face_triangles_range(OffsetIndices<int> faces, int face_i)
{
const IndexRange face = faces[face_i];
/* This is the same as #poly_to_tri_count which is not included here. */
const int start_triangle = face.start() - face_i * 2;
return IndexRange(start_triangle, face_triangles_num(face.size()));
}
/**
* Return the index of the edge's vertex that is not the \a vert.
*/

View File

@ -233,6 +233,12 @@ struct ARegionType {
/* return context data */
bContextDataCallback context;
/**
* Called on every frame in which the region's poll succeeds, regardless of visibility, before
* drawing, visibility evaluation and initialization. Allows the region to override visibility.
*/
void (*on_poll_success)(const bContext *C, ARegion *region);
/**
* Called whenever the user changes the region's size. Not called when the size is changed
* through other means, like to adjust for a scaled down window.
@ -516,6 +522,7 @@ enum AssetShelfTypeFlag {
/** Do not trigger asset dragging on drag events. Drag events can be overridden with custom
* keymap items then. */
ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG = (1 << 0),
ASSET_SHELF_TYPE_FLAG_DEFAULT_VISIBLE = (1 << 1),
ASSET_SHELF_TYPE_FLAG_MAX
};

View File

@ -268,6 +268,7 @@ static AssetTypeInfo AssetType_AC = {
IDTypeInfo IDType_ID_AC = {
/*id_code*/ ID_AC,
/*id_filter*/ FILTER_ID_AC,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_AC,
/*struct_size*/ sizeof(bAction),
/*name*/ "Action",

View File

@ -475,6 +475,8 @@ static void armature_undo_preserve(BlendLibReader * /*reader*/, ID *id_new, ID *
IDTypeInfo IDType_ID_AR = {
/*id_code*/ ID_AR,
/*id_filter*/ FILTER_ID_AR,
/* IDProps of armature bones can use any type of ID. */
/*dependencies_id_types*/ FILTER_ID_ALL,
/*main_listbase_index*/ INDEX_ID_AR,
/*struct_size*/ sizeof(bArmature),
/*name*/ "Armature",

View File

@ -426,6 +426,8 @@ static AssetTypeInfo AssetType_BR = {
IDTypeInfo IDType_ID_BR = {
/*id_code*/ ID_BR,
/*id_filter*/ FILTER_ID_BR,
/*dependencies_id_types*/
(FILTER_ID_BR | FILTER_ID_IM | FILTER_ID_PC | FILTER_ID_TE | FILTER_ID_MA),
/*main_listbase_index*/ INDEX_ID_BR,
/*struct_size*/ sizeof(Brush),
/*name*/ "Brush",

View File

@ -932,6 +932,53 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
return data->tree;
}
void BKE_bvhtree_from_mesh_tris_init(const Mesh &mesh,
const blender::IndexMask &faces_mask,
BVHTreeFromMesh &r_data)
{
using namespace blender;
using namespace blender::bke;
const Span<float3> positions = mesh.vert_positions();
const Span<int2> edges = mesh.edges();
const Span<int> corner_verts = mesh.corner_verts();
const OffsetIndices faces = mesh.faces();
const Span<int3> corner_tris = mesh.corner_tris();
bvhtree_from_mesh_setup_data(nullptr,
BVHTREE_FROM_CORNER_TRIS,
positions,
edges,
corner_verts,
corner_tris,
nullptr,
&r_data);
int tris_num = 0;
faces_mask.foreach_index(
[&](const int i) { tris_num += mesh::face_triangles_num(faces[i].size()); });
int active_num = -1;
BVHTree *tree = bvhtree_new_common(0.0f, 2, 6, tris_num, active_num);
r_data.tree = tree;
if (tree == nullptr) {
return;
}
faces_mask.foreach_index([&](const int face_i) {
const IndexRange triangles_range = mesh::face_triangles_range(faces, face_i);
for (const int tri_i : triangles_range) {
float co[3][3];
copy_v3_v3(co[0], positions[corner_verts[corner_tris[tri_i][0]]]);
copy_v3_v3(co[1], positions[corner_verts[corner_tris[tri_i][1]]]);
copy_v3_v3(co[2], positions[corner_verts[corner_tris[tri_i][2]]]);
BLI_bvhtree_insert(tree, tri_i, co[0], 3);
}
});
BLI_bvhtree_balance(tree);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -121,6 +121,7 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_CF = {
/*id_code*/ ID_CF,
/*id_filter*/ FILTER_ID_CF,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_CF,
/*struct_size*/ sizeof(CacheFile),
/*name*/ "CacheFile",

View File

@ -229,6 +229,7 @@ static void camera_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_CA = {
/*id_code*/ ID_CA,
/*id_filter*/ FILTER_ID_CA,
/*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_IM,
/*main_listbase_index*/ INDEX_ID_CA,
/*struct_size*/ sizeof(Camera),
/*name*/ "Camera",

View File

@ -352,6 +352,7 @@ static void collection_blend_read_after_liblink(BlendLibReader * /*reader*/, ID
IDTypeInfo IDType_ID_GR = {
/*id_code*/ ID_GR,
/*id_filter*/ FILTER_ID_GR,
/*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_GR,
/*main_listbase_index*/ INDEX_ID_GR,
/*struct_size*/ sizeof(Collection),
/*name*/ "Collection",

View File

@ -271,6 +271,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_CU_LEGACY = {
/*id_code*/ ID_CU_LEGACY,
/*id_filter*/ FILTER_ID_CU_LEGACY,
/*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF | FILTER_ID_KE,
/*main_listbase_index*/ INDEX_ID_CU_LEGACY,
/*struct_size*/ sizeof(Curve),
/*name*/ "Curve",

View File

@ -133,6 +133,7 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_CV = {
/*id_code*/ ID_CV,
/*id_filter*/ FILTER_ID_CV,
/*dependencies_id_types*/ FILTER_ID_MA | FILTER_ID_OB,
/*main_listbase_index*/ INDEX_ID_CV,
/*struct_size*/ sizeof(Curves),
/*name*/ "Curves",

View File

@ -264,6 +264,7 @@ static void greasepencil_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_GD_LEGACY = {
/*id_code*/ ID_GD_LEGACY,
/*id_filter*/ FILTER_ID_GD_LEGACY,
/*dependencies_id_types*/ FILTER_ID_MA,
/*main_listbase_index*/ INDEX_ID_GD_LEGACY,
/*struct_size*/ sizeof(bGPdata),
/*name*/ "GPencil",

View File

@ -214,6 +214,7 @@ static void grease_pencil_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_GP = {
/*id_code*/ ID_GP,
/*id_filter*/ FILTER_ID_GP,
/*dependencies_id_types*/ FILTER_ID_GP | FILTER_ID_MA,
/*main_listbase_index*/ INDEX_ID_GP,
/*struct_size*/ sizeof(GreasePencil),
/*name*/ "GreasePencil",

View File

@ -6,6 +6,7 @@
* \ingroup bke
*/
#include <array>
#include <cstring>
#include "MEM_guardedalloc.h"
@ -45,14 +46,17 @@ bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v)
(key_a->identifier != key_b->identifier);
}
static IDTypeInfo *id_types[INDEX_ID_MAX] = {nullptr};
static std::array<IDTypeInfo *, INDEX_ID_MAX> id_types;
static void id_type_init()
{
int init_types_num = 0;
#define INIT_TYPE(_id_code) \
{ \
BLI_assert(IDType_##_id_code.main_listbase_index == INDEX_##_id_code); \
id_types[INDEX_##_id_code] = &IDType_##_id_code; \
init_types_num++; \
} \
(void)0
@ -97,9 +101,12 @@ static void id_type_init()
INIT_TYPE(ID_VO);
INIT_TYPE(ID_GP);
/* Special naughty boy... */
/* Special case. */
BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL);
id_types[INDEX_ID_NULL] = &IDType_ID_LINK_PLACEHOLDER;
init_types_num++;
BLI_assert_msg(init_types_num == INDEX_ID_MAX, "Some IDTypeInfo initialization is missing");
#undef INIT_TYPE
}
@ -112,10 +119,11 @@ void BKE_idtype_init()
const IDTypeInfo *BKE_idtype_get_info_from_idtype_index(const int idtype_index)
{
if (idtype_index >= 0 && idtype_index < ARRAY_SIZE(id_types) &&
id_types[idtype_index] != nullptr && id_types[idtype_index]->name[0] != '\0')
{
return id_types[idtype_index];
if (idtype_index >= 0 && idtype_index < int(id_types.size())) {
const IDTypeInfo *id_type = id_types[size_t(idtype_index)];
if (id_type && id_type->name[0] != '\0') {
return id_type;
}
}
return nullptr;
@ -133,9 +141,9 @@ const IDTypeInfo *BKE_idtype_get_info_from_id(const ID *id)
static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
{
for (int i = ARRAY_SIZE(id_types); i--;) {
if (id_types[i] != nullptr && STREQ(idtype_name, id_types[i]->name)) {
return id_types[i];
for (const IDTypeInfo *id_type : id_types) {
if (id_type && STREQ(idtype_name, id_type->name)) {
return id_type;
}
}
@ -208,124 +216,6 @@ bool BKE_idtype_idcode_append_is_reusable(const short idcode)
return false;
}
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
#define CASE_IDFILTER(_id) \
case ID_##_id: \
return FILTER_ID_##_id
#define CASE_IDFILTER_NONE(_id) \
case ID_##_id: \
return 0
switch ((ID_Type)idcode) {
CASE_IDFILTER(AC);
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
CASE_IDFILTER(CF);
CASE_IDFILTER(CU_LEGACY);
CASE_IDFILTER(GD_LEGACY);
CASE_IDFILTER(GP);
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
CASE_IDFILTER_NONE(IP);
CASE_IDFILTER(KE);
CASE_IDFILTER(LA);
CASE_IDFILTER(LI);
CASE_IDFILTER(LP);
CASE_IDFILTER(LS);
CASE_IDFILTER(LT);
CASE_IDFILTER(MA);
CASE_IDFILTER(MB);
CASE_IDFILTER(MC);
CASE_IDFILTER(ME);
CASE_IDFILTER(MSK);
CASE_IDFILTER(NT);
CASE_IDFILTER(OB);
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
CASE_IDFILTER(PT);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SCR);
CASE_IDFILTER(SO);
CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(VO);
CASE_IDFILTER(WM);
CASE_IDFILTER(WO);
CASE_IDFILTER(WS);
}
BLI_assert_unreachable();
return 0;
#undef CASE_IDFILTER
#undef CASE_IDFILTER_NONE
}
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
{
#define CASE_IDFILTER(_id) \
case FILTER_ID_##_id: \
return ID_##_id
#define CASE_IDFILTER_NONE(_id) (void)0
switch (idfilter) {
CASE_IDFILTER(AC);
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
CASE_IDFILTER(CA);
CASE_IDFILTER(CF);
CASE_IDFILTER(CU_LEGACY);
CASE_IDFILTER(GD_LEGACY);
CASE_IDFILTER(GP);
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
CASE_IDFILTER_NONE(IP);
CASE_IDFILTER(KE);
CASE_IDFILTER(LA);
CASE_IDFILTER(LI);
CASE_IDFILTER(LP);
CASE_IDFILTER(LS);
CASE_IDFILTER(LT);
CASE_IDFILTER(MA);
CASE_IDFILTER(MB);
CASE_IDFILTER(MC);
CASE_IDFILTER(ME);
CASE_IDFILTER(MSK);
CASE_IDFILTER(NT);
CASE_IDFILTER(OB);
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
CASE_IDFILTER(PT);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SCR);
CASE_IDFILTER(SO);
CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(VO);
CASE_IDFILTER(WM);
CASE_IDFILTER(WO);
CASE_IDFILTER(WS);
}
BLI_assert_unreachable();
return 0;
#undef CASE_IDFILTER
#undef CASE_IDFILTER_NONE
}
int BKE_idtype_idcode_to_index(const short idcode)
{
#define CASE_IDINDEX(_id) \
@ -385,68 +275,98 @@ int BKE_idtype_idcode_to_index(const short idcode)
#undef CASE_IDINDEX
}
short BKE_idtype_idcode_from_index(const int index)
int BKE_idtype_idfilter_to_index(const uint64_t id_filter)
{
#define CASE_IDCODE(_id) \
case INDEX_ID_##_id: \
return ID_##_id
#define CASE_IDINDEX(_id) \
case FILTER_ID_##_id: \
return INDEX_ID_##_id
switch (index) {
CASE_IDCODE(AC);
CASE_IDCODE(AR);
CASE_IDCODE(BR);
CASE_IDCODE(CA);
CASE_IDCODE(CF);
CASE_IDCODE(CU_LEGACY);
CASE_IDCODE(GD_LEGACY);
CASE_IDCODE(GP);
CASE_IDCODE(GR);
CASE_IDCODE(CV);
CASE_IDCODE(IM);
CASE_IDCODE(IP);
CASE_IDCODE(KE);
CASE_IDCODE(LA);
CASE_IDCODE(LI);
CASE_IDCODE(LS);
CASE_IDCODE(LT);
CASE_IDCODE(MA);
CASE_IDCODE(MB);
CASE_IDCODE(MC);
CASE_IDCODE(ME);
CASE_IDCODE(MSK);
CASE_IDCODE(NT);
CASE_IDCODE(OB);
CASE_IDCODE(PA);
CASE_IDCODE(PAL);
CASE_IDCODE(PC);
CASE_IDCODE(PT);
CASE_IDCODE(LP);
CASE_IDCODE(SCE);
CASE_IDCODE(SCR);
CASE_IDCODE(SPK);
CASE_IDCODE(SO);
CASE_IDCODE(TE);
CASE_IDCODE(TXT);
CASE_IDCODE(VF);
CASE_IDCODE(VO);
CASE_IDCODE(WM);
CASE_IDCODE(WO);
CASE_IDCODE(WS);
switch (id_filter) {
CASE_IDINDEX(AC);
CASE_IDINDEX(AR);
CASE_IDINDEX(BR);
CASE_IDINDEX(CA);
CASE_IDINDEX(CF);
CASE_IDINDEX(CU_LEGACY);
CASE_IDINDEX(GD_LEGACY);
CASE_IDINDEX(GP);
CASE_IDINDEX(GR);
CASE_IDINDEX(CV);
CASE_IDINDEX(IM);
CASE_IDINDEX(IP);
CASE_IDINDEX(KE);
CASE_IDINDEX(LA);
CASE_IDINDEX(LI);
CASE_IDINDEX(LS);
CASE_IDINDEX(LT);
CASE_IDINDEX(MA);
CASE_IDINDEX(MB);
CASE_IDINDEX(MC);
CASE_IDINDEX(ME);
CASE_IDINDEX(MSK);
CASE_IDINDEX(NT);
CASE_IDINDEX(OB);
CASE_IDINDEX(PA);
CASE_IDINDEX(PAL);
CASE_IDINDEX(PC);
CASE_IDINDEX(PT);
CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
CASE_IDINDEX(SPK);
CASE_IDINDEX(SO);
CASE_IDINDEX(TE);
CASE_IDINDEX(TXT);
CASE_IDINDEX(VF);
CASE_IDINDEX(VO);
CASE_IDINDEX(WM);
CASE_IDINDEX(WO);
CASE_IDINDEX(WS);
}
/* Special naughty boy... */
if (index == INDEX_ID_NULL) {
return ID_LINK_PLACEHOLDER;
}
/* No handling of #ID_LINK_PLACEHOLDER or #INDEX_ID_NULL here. */
return -1;
#undef CASE_IDCODE
#undef CASE_IDINDEX
}
short BKE_idtype_idcode_iter_step(int *index)
short BKE_idtype_index_to_idcode(const int idtype_index)
{
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idtype_index(idtype_index);
if (id_type) {
return id_type->id_code;
}
BLI_assert_unreachable();
return -1;
}
uint64_t BKE_idtype_index_to_idfilter(const int idtype_index)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idtype_index(idtype_index);
if (id_type) {
return id_type->id_filter;
}
BLI_assert_unreachable();
return 0;
}
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
return BKE_idtype_index_to_idfilter(BKE_idtype_idcode_to_index(idcode));
}
short BKE_idtype_idfilter_to_idcode(const uint64_t idfilter)
{
return BKE_idtype_index_to_idcode(BKE_idtype_idfilter_to_index(idfilter));
}
short BKE_idtype_idcode_iter_step(int *idtype_index)
{
return (*idtype_index < int(id_types.size())) ? BKE_idtype_index_to_idcode((*idtype_index)++) :
0;
}
void BKE_idtype_id_foreach_cache(ID *id,

View File

@ -440,6 +440,7 @@ constexpr IDTypeInfo get_type_info()
IDTypeInfo info{};
info.id_code = ID_IM;
info.id_filter = FILTER_ID_IM;
info.dependencies_id_types = 0;
info.main_listbase_index = INDEX_ID_IM;
info.struct_size = sizeof(Image);
info.name = "Image";

View File

@ -156,7 +156,8 @@ static void ipo_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_IP = {
/*id_code*/ ID_IP,
/*id_filter*/ 0,
/*id_filter*/ FILTER_ID_IP,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_IP,
/*struct_size*/ sizeof(Ipo),
/*name*/ "Ipo",

View File

@ -191,6 +191,8 @@ static void shapekey_blend_read_after_liblink(BlendLibReader * /*reader*/, ID *i
IDTypeInfo IDType_ID_KE = {
/*id_code*/ ID_KE,
/*id_filter*/ FILTER_ID_KE,
/* Warning! key->from, could be more types in future? */
/*dependencies_id_types*/ FILTER_ID_ME | FILTER_ID_CU_LEGACY | FILTER_ID_LT,
/*main_listbase_index*/ INDEX_ID_KE,
/*struct_size*/ sizeof(Key),
/*name*/ "Key",

View File

@ -158,6 +158,7 @@ static void lattice_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_LT = {
/*id_code*/ ID_LT,
/*id_filter*/ FILTER_ID_LT,
/*dependencies_id_types*/ FILTER_ID_KE,
/*main_listbase_index*/ INDEX_ID_LT,
/*struct_size*/ sizeof(Lattice),
/*name*/ "Lattice",

View File

@ -84,6 +84,7 @@ static CLG_LogRef LOG = {"bke.lib_id"};
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
/*id_code*/ ID_LINK_PLACEHOLDER,
/*id_filter*/ 0,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_NULL,
/*struct_size*/ sizeof(ID),
/*name*/ "LinkPlaceholder",

View File

@ -396,28 +396,24 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui)
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id,
const bool include_ui,
const IDTypeInfo *owner_id_type)
{
/* any type of ID can be used in custom props. */
if (owner_id->properties) {
return FILTER_ID_ALL;
}
const short id_type_owner = GS(owner_id->name);
/* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
if (ELEM(id_type_owner, ID_NT, ID_AR)) {
return FILTER_ID_ALL;
}
/* Screen UI IDs can also link to virtually any ID (through e.g. the Outliner). */
if (include_ui && id_type_owner == ID_SCR) {
/* When including UI data (i.e. editors), Screen UI IDs can also link to virtually any ID
* (through e.g. the Outliner). */
if (include_ui && GS(owner_id->name) == ID_SCR) {
return FILTER_ID_ALL;
}
/* Casting to non const.
* TODO(jbakker): We should introduce a ntree_id_has_tree function as we are actually not
* interested in the result. */
if (ntreeFromID((ID *)owner_id)) {
if (ntreeFromID(const_cast<ID *>(owner_id))) {
return FILTER_ID_ALL;
}
@ -431,118 +427,21 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include
return FILTER_ID_ALL;
}
switch ((ID_Type)id_type_owner) {
case ID_LI:
return FILTER_ID_LI;
case ID_SCE:
return FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC | FILTER_ID_MA |
FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS | FILTER_ID_MSK | FILTER_ID_SO |
FILTER_ID_GD_LEGACY | FILTER_ID_BR | FILTER_ID_PAL | FILTER_ID_IM | FILTER_ID_NT;
case ID_OB:
/* Could be more specific, but simpler to just always say 'yes' here. */
return FILTER_ID_ALL;
case ID_ME:
return FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE;
case ID_CU_LEGACY:
return FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF | FILTER_ID_KE;
case ID_MB:
return FILTER_ID_MA;
case ID_MA:
return FILTER_ID_TE | FILTER_ID_GR;
case ID_TE:
return FILTER_ID_IM | FILTER_ID_OB;
case ID_LT:
return 0;
case ID_LA:
return FILTER_ID_TE | FILTER_ID_KE;
case ID_CA:
return FILTER_ID_OB | FILTER_ID_IM;
case ID_KE:
/* Warning! key->from, could be more types in future? */
return FILTER_ID_ME | FILTER_ID_CU_LEGACY | FILTER_ID_LT;
case ID_SCR:
return FILTER_ID_SCE;
case ID_WO:
return FILTER_ID_TE;
case ID_SPK:
return FILTER_ID_SO;
case ID_GR:
return FILTER_ID_OB | FILTER_ID_GR;
case ID_NT:
/* Could be more specific, but node.id has no type restriction... */
return FILTER_ID_ALL;
case ID_BR:
return FILTER_ID_BR | FILTER_ID_IM | FILTER_ID_PC | FILTER_ID_TE | FILTER_ID_MA;
case ID_PA:
return FILTER_ID_OB | FILTER_ID_GR | FILTER_ID_TE;
case ID_MC:
return FILTER_ID_GD_LEGACY | FILTER_ID_IM;
case ID_MSK:
/* WARNING! mask->parent.id, not typed. */
return FILTER_ID_MC;
case ID_LS:
return FILTER_ID_TE | FILTER_ID_OB;
case ID_LP:
return FILTER_ID_IM;
case ID_GD_LEGACY:
return FILTER_ID_MA;
case ID_GP:
return FILTER_ID_GP | FILTER_ID_MA;
case ID_WS:
return FILTER_ID_SCE;
case ID_CV:
return FILTER_ID_MA | FILTER_ID_OB;
case ID_PT:
return FILTER_ID_MA;
case ID_VO:
return FILTER_ID_MA;
case ID_WM:
return FILTER_ID_SCE | FILTER_ID_WS;
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
case ID_AR:
case ID_AC:
case ID_PAL:
case ID_PC:
case ID_CF:
/* Those types never use/reference other IDs... */
return 0;
case ID_IP:
/* Deprecated... */
return 0;
if (!owner_id_type) {
owner_id_type = BKE_idtype_get_info_from_id(owner_id);
}
if (owner_id_type) {
return owner_id_type->dependencies_id_types;
}
BLI_assert_unreachable();
return 0;
}
bool BKE_library_id_can_use_idtype(ID *owner_id, const short id_type_used)
{
/* any type of ID can be used in custom props. */
if (owner_id->properties) {
return true;
}
const short id_type_owner = GS(owner_id->name);
/* Exception for ID_LI as they don't exist as a filter. */
if (id_type_used == ID_LI) {
return id_type_owner == ID_LI;
}
/* Exception: ID_KE aren't available as filter_id. */
if (id_type_used == ID_KE) {
return ELEM(id_type_owner, ID_ME, ID_CU_LEGACY, ID_LT);
}
/* Exception: ID_SCR aren't available as filter_id. */
if (id_type_used == ID_SCR) {
return ELEM(id_type_owner, ID_WS);
}
const IDTypeInfo *owner_id_type = BKE_idtype_get_info_from_id(owner_id);
const uint64_t filter_id_type_used = BKE_idtype_idcode_to_idfilter(id_type_used);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(owner_id, false);
const uint64_t can_be_used = BKE_library_id_can_use_filter_id(owner_id, false, owner_id_type);
return (can_be_used & filter_id_type_used) != 0;
}

View File

@ -81,6 +81,7 @@ static void library_blend_read_data(BlendDataReader * /*reader*/, ID *id)
IDTypeInfo IDType_ID_LI = {
/*id_code*/ ID_LI,
/*id_filter*/ FILTER_ID_LI,
/*dependencies_id_types*/ FILTER_ID_LI,
/*main_listbase_index*/ INDEX_ID_LI,
/*struct_size*/ sizeof(Library),
/*name*/ "Library",

View File

@ -152,6 +152,7 @@ static void light_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_LA = {
/*id_code*/ ID_LA,
/*id_filter*/ FILTER_ID_LA,
/*dependencies_id_types*/ FILTER_ID_TE,
/*main_listbase_index*/ INDEX_ID_LA,
/*struct_size*/ sizeof(Light),
/*name*/ "Light",

View File

@ -53,6 +53,7 @@ static void lightprobe_blend_write(BlendWriter *writer, ID *id, const void *id_a
IDTypeInfo IDType_ID_LP = {
/*id_code*/ ID_LP,
/*id_filter*/ FILTER_ID_LP,
/*dependencies_id_types*/ FILTER_ID_IM,
/*main_listbase_index*/ INDEX_ID_LP,
/*struct_size*/ sizeof(LightProbe),
/*name*/ "LightProbe",

View File

@ -643,6 +643,7 @@ static void linestyle_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_LS = {
/*id_code*/ ID_LS,
/*id_filter*/ FILTER_ID_LS,
/*dependencies_id_types*/ FILTER_ID_TE | FILTER_ID_OB,
/*main_listbase_index*/ INDEX_ID_LS,
/*struct_size*/ sizeof(FreestyleLineStyle),
/*name*/ "FreestyleLineStyle",

View File

@ -184,6 +184,7 @@ static void mask_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_MSK = {
/*id_code*/ ID_MSK,
/*id_filter*/ FILTER_ID_MSK,
/*dependencies_id_types*/ FILTER_ID_MC, /* WARNING! mask->parent.id, not typed. */
/*main_listbase_index*/ INDEX_ID_MSK,
/*struct_size*/ sizeof(Mask),
/*name*/ "Mask",

View File

@ -231,6 +231,7 @@ static void material_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_MA = {
/*id_code*/ ID_MA,
/*id_filter*/ FILTER_ID_MA,
/*dependencies_id_types*/ FILTER_ID_TE | FILTER_ID_GR,
/*main_listbase_index*/ INDEX_ID_MA,
/*struct_size*/ sizeof(Material),
/*name*/ "Material",

View File

@ -140,6 +140,7 @@ static void metaball_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_MB = {
/*id_code*/ ID_MB,
/*id_filter*/ FILTER_ID_MB,
/*dependencies_id_types*/ FILTER_ID_MA,
/*main_listbase_index*/ INDEX_ID_MB,
/*struct_size*/ sizeof(MetaBall),
/*name*/ "Metaball",

View File

@ -383,6 +383,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_ME = {
/*id_code*/ ID_ME,
/*id_filter*/ FILTER_ID_ME,
/*dependencies_id_types*/ FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE,
/*main_listbase_index*/ INDEX_ID_ME,
/*struct_size*/ sizeof(Mesh),
/*name*/ "Mesh",

View File

@ -279,6 +279,7 @@ static void movieclip_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_MC = {
/*id_code*/ ID_MC,
/*id_filter*/ FILTER_ID_MC,
/*dependencies_id_types*/ FILTER_ID_GD_LEGACY | FILTER_ID_IM,
/*main_listbase_index*/ INDEX_ID_MC,
/*struct_size*/ sizeof(MovieClip),
/*name*/ "MovieClip",

View File

@ -1272,6 +1272,8 @@ static AssetTypeInfo AssetType_NT = {
IDTypeInfo IDType_ID_NT = {
/*id_code*/ ID_NT,
/*id_filter*/ FILTER_ID_NT,
/* IDProps of nodes, and #bNode.id, can use any type of ID. */
/*dependencies_id_types*/ FILTER_ID_ALL,
/*main_listbase_index*/ INDEX_ID_NT,
/*struct_size*/ sizeof(bNodeTree),
/*name*/ "NodeTree",

View File

@ -1077,6 +1077,8 @@ static AssetTypeInfo AssetType_OB = {
IDTypeInfo IDType_ID_OB = {
/*id_code*/ ID_OB,
/*id_filter*/ FILTER_ID_OB,
/* Could be more specific, but simpler to just always say 'yes' here. */
/*dependencies_id_types*/ FILTER_ID_ALL,
/*main_listbase_index*/ INDEX_ID_OB,
/*struct_size*/ sizeof(Object),
/*name*/ "Object",

View File

@ -147,6 +147,7 @@ static void palette_undo_preserve(BlendLibReader * /*reader*/, ID *id_new, ID *i
IDTypeInfo IDType_ID_PAL = {
/*id_code*/ ID_PAL,
/*id_filter*/ FILTER_ID_PAL,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_PAL,
/*struct_size*/ sizeof(Palette),
/*name*/ "Palette",
@ -214,6 +215,7 @@ static void paint_curve_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_PC = {
/*id_code*/ ID_PC,
/*id_filter*/ FILTER_ID_PC,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_PC,
/*struct_size*/ sizeof(PaintCurve),
/*name*/ "PaintCurve",

View File

@ -379,6 +379,7 @@ static void particle_settings_blend_read_after_liblink(BlendLibReader * /*reader
IDTypeInfo IDType_ID_PA = {
/*id_code*/ ID_PA,
/*id_filter*/ FILTER_ID_PA,
/*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_GR | FILTER_ID_TE,
/*main_listbase_index*/ INDEX_ID_PA,
/*struct_size*/ sizeof(ParticleSettings),
/*name*/ "ParticleSettings",

View File

@ -146,6 +146,7 @@ static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_PT = {
/*id_code*/ ID_PT,
/*id_filter*/ FILTER_ID_PT,
/*dependencies_id_types*/ FILTER_ID_MA,
/*main_listbase_index*/ INDEX_ID_PT,
/*struct_size*/ sizeof(PointCloud),
/*name*/ "PointCloud",

View File

@ -1604,6 +1604,10 @@ constexpr IDTypeInfo get_type_info()
IDTypeInfo info{};
info.id_code = ID_SCE;
info.id_filter = FILTER_ID_SCE;
info.dependencies_id_types = (FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC |
FILTER_ID_MA | FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS |
FILTER_ID_MSK | FILTER_ID_SO | FILTER_ID_GD_LEGACY | FILTER_ID_BR |
FILTER_ID_PAL | FILTER_ID_IM | FILTER_ID_NT);
info.main_listbase_index = INDEX_ID_SCE;
info.struct_size = sizeof(Scene);
info.name = "Scene";

View File

@ -159,6 +159,9 @@ static void screen_blend_read_after_liblink(BlendLibReader *reader, ID *id)
IDTypeInfo IDType_ID_SCR = {
/*id_code*/ ID_SCR,
/*id_filter*/ FILTER_ID_SCR,
/* NOTE: Can actually link to any ID type through UI (e.g. Outliner Editor). This is handled
separately though. */
/*dependencies_id_types*/ FILTER_ID_SCE,
/*main_listbase_index*/ INDEX_ID_SCR,
/*struct_size*/ sizeof(bScreen),
/*name*/ "Screen",

View File

@ -189,6 +189,7 @@ static void sound_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_SO = {
/*id_code*/ ID_SO,
/*id_filter*/ FILTER_ID_SO,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_SO,
/*struct_size*/ sizeof(bSound),
/*name*/ "Sound",

View File

@ -51,6 +51,7 @@ static void speaker_blend_write(BlendWriter *writer, ID *id, const void *id_addr
IDTypeInfo IDType_ID_SPK = {
/*id_code*/ ID_SPK,
/*id_filter*/ FILTER_ID_SPK,
/*dependencies_id_types*/ FILTER_ID_SO,
/*main_listbase_index*/ INDEX_ID_SPK,
/*struct_size*/ sizeof(Speaker),
/*name*/ "Speaker",

View File

@ -222,6 +222,7 @@ static void text_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_TXT = {
/*id_code*/ ID_TXT,
/*id_filter*/ FILTER_ID_TXT,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_TXT,
/*struct_size*/ sizeof(Text),
/*name*/ "Text",

View File

@ -188,6 +188,7 @@ static void texture_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_TE = {
/*id_code*/ ID_TE,
/*id_filter*/ FILTER_ID_TE,
/*dependencies_id_types*/ FILTER_ID_IM | FILTER_ID_OB,
/*main_listbase_index*/ INDEX_ID_TE,
/*struct_size*/ sizeof(Tex),
/*name*/ "Texture",

View File

@ -163,6 +163,7 @@ static void vfont_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_VF = {
/*id_code*/ ID_VF,
/*id_filter*/ FILTER_ID_VF,
/*dependencies_id_types*/ 0,
/*main_listbase_index*/ INDEX_ID_VF,
/*struct_size*/ sizeof(VFont),
/*name*/ "Font",

View File

@ -273,6 +273,7 @@ static void volume_blend_read_after_liblink(BlendLibReader * /*reader*/, ID *id)
IDTypeInfo IDType_ID_VO = {
/*id_code*/ ID_VO,
/*id_filter*/ FILTER_ID_VO,
/*dependencies_id_types*/ FILTER_ID_MA,
/*main_listbase_index*/ INDEX_ID_VO,
/*struct_size*/ sizeof(Volume),
/*name*/ "Volume",

View File

@ -169,6 +169,7 @@ static void workspace_blend_read_after_liblink(BlendLibReader *reader, ID *id)
IDTypeInfo IDType_ID_WS = {
/*id_code*/ ID_WS,
/*id_filter*/ FILTER_ID_WS,
/*dependencies_id_types*/ FILTER_ID_SCE,
/*main_listbase_index*/ INDEX_ID_WS,
/*struct_size*/ sizeof(WorkSpace),
/*name*/ "WorkSpace",

View File

@ -177,6 +177,7 @@ static void world_blend_read_data(BlendDataReader *reader, ID *id)
IDTypeInfo IDType_ID_WO = {
/*id_code*/ ID_WO,
/*id_filter*/ FILTER_ID_WO,
/*dependencies_id_types*/ FILTER_ID_TE,
/*main_listbase_index*/ INDEX_ID_WO,
/*struct_size*/ sizeof(World),
/*name*/ "World",

View File

@ -45,6 +45,7 @@ void region_on_user_resize(const ARegion *region);
void region_listen(const wmRegionListenerParams *params);
void region_layout(const bContext *C, ARegion *region);
void region_draw(const bContext *C, ARegion *region);
void region_on_poll_success(const bContext *C, ARegion *region);
void region_blend_read_data(BlendDataReader *reader, ARegion *region);
void region_blend_write(BlendWriter *writer, ARegion *region);
int region_prefsizey(void);

View File

@ -13,6 +13,7 @@
#include "AS_asset_catalog_path.hh"
#include "AS_asset_library.hh"
#include "BLI_function_ref.hh"
#include "BLI_string.h"
#include "BKE_context.hh"
@ -134,12 +135,15 @@ static void activate_shelf(RegionAssetShelf &shelf_regiondata, AssetShelf &shelf
*
* The returned shelf is guaranteed to have its #AssetShelf.type pointer set.
*
* \param on_create: Function called when a new asset shelf is created (case 3).
*
* \return A non-owning pointer to the now active shelf. Might be null if no shelf is valid in
* current context (all polls failed).
*/
static AssetShelf *update_active_shelf(const bContext &C,
SpaceType &space_type,
RegionAssetShelf &shelf_regiondata)
RegionAssetShelf &shelf_regiondata,
FunctionRef<void(AssetShelf &new_shelf)> on_create)
{
/* Note: Don't access #AssetShelf.type directly, use #asset_shelf_type_ensure(). */
@ -174,6 +178,9 @@ static AssetShelf *update_active_shelf(const bContext &C,
BLI_addhead(&shelf_regiondata.shelves, new_shelf);
/* Moves ownership to the regiondata. */
activate_shelf(shelf_regiondata, *new_shelf);
if (on_create) {
on_create(*new_shelf);
}
return new_shelf;
}
}
@ -267,13 +274,13 @@ void region_listen(const wmRegionListenerParams *params)
void region_init(wmWindowManager *wm, ARegion *region)
{
if (!region->regiondata) {
region->regiondata = MEM_cnew<RegionAssetShelf>("RegionAssetShelf");
}
RegionAssetShelf &shelf_regiondata = *RegionAssetShelf::get_from_asset_shelf_region(*region);
/* Region-data should've been created by a previously called #region_before_redraw(). */
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::get_from_asset_shelf_region(*region);
BLI_assert_msg(
shelf_regiondata,
"Region-data should've been created by a previously called `region_before_redraw()`.");
/* Active shelf is only set on draw, so this may be null! */
AssetShelf *active_shelf = shelf_regiondata.active_shelf;
AssetShelf *active_shelf = shelf_regiondata->active_shelf;
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_PANELS_UI, region->winx, region->winy);
@ -417,17 +424,12 @@ int region_prefsizey()
void region_layout(const bContext *C, ARegion *region)
{
const SpaceLink *space = CTX_wm_space_data(C);
SpaceType *space_type = BKE_spacetype_from_id(space->spacetype);
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::get_from_asset_shelf_region(*region);
if (!shelf_regiondata) {
/* Region-data should've been created by a previously called #region_init(). */
BLI_assert_unreachable();
return;
}
BLI_assert_msg(
shelf_regiondata,
"Region-data should've been created by a previously called `region_before_redraw()`.");
AssetShelf *active_shelf = update_active_shelf(*C, *space_type, *shelf_regiondata);
const AssetShelf *active_shelf = shelf_regiondata->active_shelf;
if (!active_shelf) {
return;
}
@ -479,6 +481,34 @@ void region_draw(const bContext *C, ARegion *region)
UI_view2d_scrollers_draw(&region->v2d, nullptr);
}
void region_on_poll_success(const bContext *C, ARegion *region)
{
ScrArea *area = CTX_wm_area(C);
BLI_assert(region->regiontype == RGN_TYPE_ASSET_SHELF);
if (!region->regiondata) {
region->regiondata = MEM_cnew<RegionAssetShelf>("RegionAssetShelf");
}
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::get_from_asset_shelf_region(*region);
if (!shelf_regiondata) {
BLI_assert_unreachable();
return;
}
update_active_shelf(
*C, *area->type, *shelf_regiondata, /*on_create=*/[&](AssetShelf &new_shelf) {
/* Update region visibility (`'DEFAULT_VISIBLE'` option). */
const int old_flag = region->flag;
SET_FLAG_FROM_TEST(region->flag,
(new_shelf.type->flag & ASSET_SHELF_TYPE_FLAG_DEFAULT_VISIBLE) == 0,
RGN_FLAG_HIDDEN);
if (old_flag != region->flag) {
ED_region_visibility_change_update(const_cast<bContext *>(C), area, region);
}
});
}
void header_region_listen(const wmRegionListenerParams *params)
{
asset_shelf_region_listen(params);
@ -493,15 +523,6 @@ void header_region_init(wmWindowManager * /*wm*/, ARegion *region)
void header_region(const bContext *C, ARegion *region)
{
const SpaceLink *space = CTX_wm_space_data(C);
SpaceType *space_type = BKE_spacetype_from_id(space->spacetype);
const ARegion *main_shelf_region = BKE_area_find_region_type(CTX_wm_area(C),
RGN_TYPE_ASSET_SHELF);
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::get_from_asset_shelf_region(
*main_shelf_region);
update_active_shelf(*C, *space_type, *shelf_regiondata);
ED_region_header_with_button_sections(C, region, uiButtonSectionsAlign::Bottom);
}

View File

@ -44,7 +44,8 @@ static void draw_node_input(bContext *C,
BLI_assert(socket.typeinfo != nullptr);
/* Ignore disabled sockets and linked sockets and sockets without a `draw` callback. */
if (!socket.is_available() || (socket.flag & (SOCK_IS_LINKED | SOCK_HIDE_VALUE)) ||
socket.typeinfo->draw == nullptr || ELEM(socket.type, SOCK_GEOMETRY, SOCK_MATRIX))
socket.typeinfo->draw == nullptr ||
ELEM(socket.type, SOCK_GEOMETRY, SOCK_MATRIX, SOCK_SHADER))
{
return;
}

View File

@ -2019,6 +2019,9 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
area_azone_init(win, screen, area);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->flag & RGN_FLAG_POLL_FAILED) {
continue;
}
region_evaulate_visibility(region);
/* region size may have changed, init does necessary adjustments */

View File

@ -755,6 +755,9 @@ static void screen_regions_poll(bContext *C, const wmWindow *win, bScreen *scree
if (region_poll(C, screen, area, region) == false) {
region->flag |= RGN_FLAG_POLL_FAILED;
}
else if (region->type && region->type->on_poll_success) {
region->type->on_poll_success(C, region);
}
if (old_region_flag != region->flag) {
any_changed = true;

View File

@ -2024,6 +2024,17 @@ static int paint_mask_gesture_line_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int face_set_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
return WM_gesture_box_invoke(C, op, event);
}
static int face_set_gesture_box_exec(bContext *C, wmOperator *op)
{
SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op);
@ -2036,6 +2047,17 @@ static int face_set_gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int face_set_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
return WM_gesture_lasso_invoke(C, op, event);
}
static int face_set_gesture_lasso_exec(bContext *C, wmOperator *op)
{
SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op);
@ -2228,7 +2250,7 @@ void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
ot->idname = "SCULPT_OT_face_set_lasso_gesture";
ot->description = "Add face set within the lasso as you move the brush";
ot->invoke = WM_gesture_lasso_invoke;
ot->invoke = face_set_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = face_set_gesture_lasso_exec;
@ -2247,7 +2269,7 @@ void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot)
ot->idname = "SCULPT_OT_face_set_box_gesture";
ot->description = "Add face set within the box as you move the brush";
ot->invoke = WM_gesture_box_invoke;
ot->invoke = face_set_gesture_box_invoke;
ot->modal = WM_gesture_box_modal;
ot->exec = face_set_gesture_box_exec;

View File

@ -1455,6 +1455,14 @@ static bool brush_asset_delete_poll(bContext *C)
return false;
}
/* Asset brush, check if belongs to an editable blend file. */
if (paint->brush_asset_reference && BKE_paint_brush_is_valid_asset(brush)) {
if (!asset_is_editable(*paint->brush_asset_reference)) {
CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable");
return false;
}
}
return true;
}

View File

@ -25,6 +25,7 @@
#include "BKE_collision.h"
#include "BKE_colortools.hh"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_mesh.hh"
#include "BKE_modifier.hh"
#include "BKE_paint.hh"
@ -1530,6 +1531,12 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
const eSculptClothFilterType filter_type = eSculptClothFilterType(RNA_enum_get(op->ptr, "type"));
/* Update the active vertex */

View File

@ -37,6 +37,7 @@
#include "BKE_colortools.hh"
#include "BKE_context.hh"
#include "BKE_customdata.hh"
#include "BKE_layer.hh"
#include "BKE_mesh.hh"
#include "BKE_mesh_fair.hh"
#include "BKE_mesh_mapping.hh"
@ -557,6 +558,12 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
const CreateMode mode = CreateMode(RNA_enum_get(op->ptr, "mode"));
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
if (BKE_pbvh_type(ss.pbvh) == PBVH_BMESH) {
/* Dyntopo not supported. */
return OPERATOR_CANCELLED;
@ -780,6 +787,12 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
const InitMode mode = InitMode(RNA_enum_get(op->ptr, "mode"));
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
/* Dyntopo not supported. */
@ -1126,6 +1139,12 @@ static int sculpt_face_set_change_visibility_invoke(bContext *C,
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
/* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
* cursor updates. */
SculptCursorGeometryInfo sgi;
@ -1174,6 +1193,12 @@ static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator * /*op
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
/* Dyntopo not supported. */
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
return OPERATOR_CANCELLED;
@ -1546,6 +1571,12 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
/* Update the current active Face Set and Vertex as the operator can be used directly from the

View File

@ -18,6 +18,7 @@
#include "DNA_userdef_types.h"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_paint.hh"
#include "BKE_pbvh_api.hh"
@ -330,6 +331,11 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op)
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
int mval[2];
RNA_int_get_array(op->ptr, "start_mouse", mval);
float mval_fl[2] = {float(mval[0]), float(mval[1])};

View File

@ -11,6 +11,7 @@
#include "BLI_task.h"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_paint.hh"
#include "BKE_pbvh_api.hh"
@ -160,6 +161,12 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
const Scene *scene = CTX_data_scene(C);
int filter_type = RNA_enum_get(op->ptr, "filter_type");
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
BKE_sculpt_mask_layers_ensure(CTX_data_depsgraph_pointer(C), CTX_data_main(C), ob, mmd);

View File

@ -24,6 +24,8 @@
#include "BKE_brush.hh"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_modifier.hh"
#include "BKE_object_types.hh"
#include "BKE_paint.hh"
#include "BKE_pbvh_api.hh"
@ -948,6 +950,13 @@ static int sculpt_mesh_filter_start(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
int mval[2];
RNA_int_get_array(op->ptr, "start_mouse", mval);

View File

@ -16,6 +16,7 @@
#include "BKE_ccg.h"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_multires.hh"
#include "BKE_paint.hh"
#include "BKE_pbvh_api.hh"
@ -80,6 +81,12 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
SculptSession *ss = ob->sculpt;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
const int mode = RNA_enum_get(op->ptr, "mode");
MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);

View File

@ -638,6 +638,12 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
BKE_sculpt_update_object_for_edit(CTX_data_depsgraph_pointer(C), ob, false);
/* No color attribute? Set color to white. */
@ -902,14 +908,19 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
{
View3D *v3d = CTX_wm_view3d(C);
if (v3d && v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
}
}
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
/* Color data is not available in multi-resolution or dynamic topology. */
if (!SCULPT_handles_colors_report(ss, op->reports)) {
return OPERATOR_CANCELLED;
@ -1067,6 +1078,12 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
const Brush *brush = BKE_paint_brush(&sd->paint);
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob);
BKE_sculpt_mask_layers_ensure(depsgraph, CTX_data_main(C), ob, mmd);

View File

@ -16,6 +16,7 @@
#include "BKE_brush.hh"
#include "BKE_context.hh"
#include "BKE_kelvinlet.h"
#include "BKE_layer.hh"
#include "BKE_paint.hh"
#include "BKE_pbvh_api.hh"
@ -385,6 +386,12 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
int mode = RNA_enum_get(op->ptr, "mode");
const View3D *v3d = CTX_wm_view3d(C);
const Base *base = CTX_data_active_base(C);
if (!BKE_base_is_visible(v3d, base)) {
return OPERATOR_CANCELLED;
}
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
/* Pivot to center. */

View File

@ -2151,8 +2151,8 @@ static void unused_message_gen(std::string &message,
(is_first) ? "" : ", ",
num_tagged[i],
(num_tagged[i] > 1) ?
IFACE_(BKE_idtype_idcode_to_name_plural(BKE_idtype_idcode_from_index(i))) :
IFACE_(BKE_idtype_idcode_to_name(BKE_idtype_idcode_from_index(i))));
IFACE_(BKE_idtype_idcode_to_name_plural(BKE_idtype_index_to_idcode(i))) :
IFACE_(BKE_idtype_idcode_to_name(BKE_idtype_index_to_idcode(i))));
is_first = false;
}
}

View File

@ -2196,6 +2196,7 @@ void ED_spacetype_view3d()
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_FRAMES;
art->duplicate = asset::shelf::region_duplicate;
art->free = asset::shelf::region_free;
art->on_poll_success = asset::shelf::region_on_poll_success;
art->listener = asset::shelf::region_listen;
art->poll = asset::shelf::regions_poll;
art->snap_size = asset::shelf::region_snap;

View File

@ -1492,7 +1492,20 @@ static void drawTransformView(const bContext * /*C*/, ARegion *region, void *arg
GPU_line_width(1.0f);
drawConstraint(t);
drawPropCircle(t);
switch (t->spacetype) {
case SPACE_GRAPH:
case SPACE_ACTION:
/* Different visualization because the proportional editing in these editors only looks at
* the x-axis. */
drawPropRange(t);
break;
default:
drawPropCircle(t);
break;
}
drawSnapping(t);
if (region == t->region && t->mode_info && t->mode_info->draw_fn) {

View File

@ -904,15 +904,6 @@ void drawPropCircle(TransInfo *t)
else if (t->spacetype == SPACE_IMAGE) {
GPU_matrix_scale_2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]);
}
else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
/* only scale y */
float xscale, yscale;
UI_view2d_scale_get(&t->region->v2d, &xscale, &yscale);
const float fac_scale = xscale / yscale;
GPU_matrix_scale_2f(1.0f, fac_scale);
GPU_matrix_translate_2f(0.0f, (t->center_global[1] / fac_scale) - t->center_global[1]);
}
eGPUDepthTest depth_test_enabled = GPU_depth_test_get();
if (depth_test_enabled) {
@ -947,6 +938,40 @@ void drawPropCircle(TransInfo *t)
}
}
void drawPropRange(TransInfo *t)
{
if ((t->flag & T_PROP_EDIT) == 0) {
return;
}
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
float viewport[4];
GPU_viewport_size_get_f(viewport);
GPU_blend(GPU_BLEND_ALPHA);
immUniform2fv("viewportSize", &viewport[2]);
View2D *v2d = &t->region->v2d;
const float x1 = t->center_global[0] - t->prop_size;
const float y1 = v2d->cur.ymin;
const float x2 = t->center_global[0] + t->prop_size;
const float y2 = v2d->cur.ymax;
immUniform1f("lineWidth", 3.0f * U.pixelsize);
immUniformThemeColorShadeAlpha(TH_GRID, -20, 255);
imm_draw_box_wire_3d(pos, x1, y1, x2, y2);
immUniform1f("lineWidth", 1.0f * U.pixelsize);
immUniformThemeColorShadeAlpha(TH_GRID, 20, 255);
imm_draw_box_wire_3d(pos, x1, y1, x2, y2);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
static void drawObjectConstraint(TransInfo *t)
{
/* Draw the first one lighter because that's the one who controls the others.

View File

@ -41,6 +41,10 @@ void drawConstraint(TransInfo *t);
* Called from drawview.c, as an extra per-window draw option.
*/
void drawPropCircle(TransInfo *t);
/**
* Draws two lines to indicate a proportional editing range that is only defined in one axis.
*/
void drawPropRange(TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
void initSelectConstraint(TransInfo *t);

View File

@ -1209,6 +1209,7 @@ typedef enum IDRecalcFlag {
#define FILTER_ID_WM (1ULL << 38)
#define FILTER_ID_LI (1ULL << 39)
#define FILTER_ID_GP (1ULL << 40)
#define FILTER_ID_IP (1ULL << 41)
#define FILTER_ID_ALL \
(FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU_LEGACY | \
@ -1217,7 +1218,8 @@ typedef enum IDRecalcFlag {
FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | \
FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | \
FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | \
FILTER_ID_SIM | FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI | FILTER_ID_GP)
FILTER_ID_SIM | FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI | FILTER_ID_GP | \
FILTER_ID_IP)
/**
* This enum defines the index assigned to each type of IDs in the array returned by

View File

@ -82,9 +82,7 @@ enum {
* };
*
* // Access all triangles in a given face.
* const IndexRange face = faces[i];
* const Span<int3> corner_tris = corner_tris.slice(poly_to_tri_count(i, face.start()),
* bke::mesh::face_triangles_num(face.size()));
* const Span<int3> corner_tris = corner_tris.slice(face_triangles_range(faces, i));
* \endcode
*
* It may also be useful to check whether or not two vertices of a triangle form an edge in the

View File

@ -2303,6 +2303,12 @@ static void rna_def_asset_shelf(BlenderRNA *brna)
"No Asset Dragging",
"Disable the default asset dragging on drag events. Useful for implementing custom "
"dragging via custom key-map items"},
{ASSET_SHELF_TYPE_FLAG_DEFAULT_VISIBLE,
"DEFAULT_VISIBLE",
0,
"Visible by Default",
"Unhide the asset shelf when it's available for the first time, otherwise it will be "
"hidden"},
{0, nullptr, 0, nullptr, nullptr},
};

View File

@ -14,6 +14,8 @@
#include "RNA_enum_types.hh"
#include "BLI_task.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_sample_nearest_surface_cc {
@ -29,12 +31,22 @@ static void node_declare(NodeDeclarationBuilder &b)
const eCustomDataType data_type = eCustomDataType(node->custom1);
b.add_input(data_type, "Value").hide_value().field_on_all();
}
b.add_input<decl::Int>("Group ID")
.hide_value()
.field_on_all()
.description(
"Splits the faces of the input mesh into groups which can be sampled individually");
b.add_input<decl::Vector>("Sample Position").implicit_field(implicit_field_inputs::position);
b.add_input<decl::Int>("Sample Group ID").hide_value().supports_field();
if (node != nullptr) {
const eCustomDataType data_type = eCustomDataType(node->custom1);
b.add_output(data_type, "Value").dependent_field({2});
b.add_output(data_type, "Value").dependent_field({3, 4});
}
b.add_output<decl::Bool>("Is Valid")
.dependent_field({3, 4})
.description(
"Whether the sampling was successfull. It can fail when the sampled group is empty");
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
@ -64,46 +76,105 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
static void get_closest_mesh_tris(const Mesh &mesh,
const VArray<float3> &positions,
const IndexMask &mask,
const MutableSpan<int> r_tri_indices,
const MutableSpan<float> r_distances_sq,
const MutableSpan<float3> r_positions)
{
BLI_assert(mesh.faces_num > 0);
BVHTreeFromMesh tree_data;
BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_CORNER_TRIS, 2);
get_closest_in_bvhtree(tree_data, positions, mask, r_tri_indices, r_distances_sq, r_positions);
free_bvhtree_from_mesh(&tree_data);
}
class SampleNearestSurfaceFunction : public mf::MultiFunction {
private:
GeometrySet source_;
Array<BVHTreeFromMesh> bvh_trees_;
VectorSet<int> group_indices_;
public:
SampleNearestSurfaceFunction(GeometrySet geometry) : source_(std::move(geometry))
SampleNearestSurfaceFunction(GeometrySet geometry, const Field<int> &group_id_field)
: source_(std::move(geometry))
{
source_.ensure_owns_direct_data();
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Sample Nearest Surface", signature};
builder.single_input<float3>("Position");
builder.single_input<int>("Sample ID");
builder.single_output<int>("Triangle Index");
builder.single_output<float3>("Sample Position");
builder.single_output<bool>("Is Valid", mf::ParamFlag::SupportsUnusedOutput);
return signature;
}();
this->set_signature(&signature);
const Mesh &mesh = *source_.get_mesh();
/* Compute group ids on mesh. */
bke::MeshFieldContext field_context{mesh, bke::AttrDomain::Face};
FieldEvaluator field_evaluator{field_context, mesh.faces_num};
field_evaluator.add(group_id_field);
field_evaluator.evaluate();
VArraySpan<int> group_ids_span = field_evaluator.get_evaluated<int>(0);
/* Compute an #IndexMask for every unique group id. */
group_indices_.add_multiple(group_ids_span);
const int groups_num = group_indices_.size();
IndexMaskMemory memory;
Array<IndexMask> group_masks(groups_num);
IndexMask::from_groups<int>(
IndexMask(mesh.faces_num),
memory,
[&](const int i) { return group_indices_.index_of(group_ids_span[i]); },
group_masks);
/* Construct BVH tree for each group. */
bvh_trees_.reinitialize(groups_num);
threading::parallel_for(IndexRange(groups_num), 16, [&](const IndexRange range) {
for (const int group_i : range) {
const IndexMask &group_mask = group_masks[group_i];
BVHTreeFromMesh &bvh = bvh_trees_[group_i];
if (group_mask.size() == mesh.faces_num) {
BKE_bvhtree_from_mesh_get(&bvh, &mesh, BVHTREE_FROM_CORNER_TRIS, 2);
}
else {
BKE_bvhtree_from_mesh_tris_init(mesh, group_mask, bvh);
}
}
});
}
~SampleNearestSurfaceFunction()
{
for (BVHTreeFromMesh &tree : bvh_trees_) {
free_bvhtree_from_mesh(&tree);
}
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
MutableSpan<int> triangle_index = params.uninitialized_single_output<int>(1, "Triangle Index");
const VArray<int> &sample_ids = params.readonly_single_input<int>(1, "Sample ID");
MutableSpan<int> triangle_index = params.uninitialized_single_output<int>(2, "Triangle Index");
MutableSpan<float3> sample_position = params.uninitialized_single_output<float3>(
2, "Sample Position");
const Mesh &mesh = *source_.get_mesh();
get_closest_mesh_tris(mesh, positions, mask, triangle_index, {}, sample_position);
3, "Sample Position");
MutableSpan<bool> is_valid_span = params.uninitialized_single_output_if_required<bool>(
4, "Is Valid");
mask.foreach_index([&](const int i) {
const float3 position = positions[i];
const int sample_id = sample_ids[i];
const int group_index = group_indices_.index_of_try(sample_id);
if (group_index == -1) {
triangle_index[i] = -1;
sample_position[i] = float3(0, 0, 0);
if (!is_valid_span.is_empty()) {
is_valid_span[i] = false;
}
return;
}
const BVHTreeFromMesh &bvh = bvh_trees_[group_index];
BVHTreeNearest nearest;
nearest.dist_sq = FLT_MAX;
BLI_bvhtree_find_nearest(
bvh.tree, position, &nearest, bvh.nearest_callback, const_cast<BVHTreeFromMesh *>(&bvh));
triangle_index[i] = nearest.index;
sample_position[i] = nearest.co;
if (!is_valid_span.is_empty()) {
is_valid_span[i] = true;
}
});
}
ExecutionHints get_execution_hints() const override
@ -133,10 +204,13 @@ static void node_geo_exec(GeoNodeExecParams params)
}
auto nearest_op = FieldOperation::Create(
std::make_shared<SampleNearestSurfaceFunction>(geometry),
{params.extract_input<Field<float3>>("Sample Position")});
std::make_shared<SampleNearestSurfaceFunction>(geometry,
params.extract_input<Field<int>>("Group ID")),
{params.extract_input<Field<float3>>("Sample Position"),
params.extract_input<Field<int>>("Sample Group ID")});
Field<int> triangle_indices(nearest_op, 0);
Field<float3> nearest_positions(nearest_op, 1);
Field<bool> is_valid(nearest_op, 2);
Field<float3> bary_weights = Field<float3>(FieldOperation::Create(
std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(geometry),
@ -148,6 +222,7 @@ static void node_geo_exec(GeoNodeExecParams params)
{triangle_indices, bary_weights});
params.set_output("Value", GField(sample_op));
params.set_output("Is Valid", is_valid);
}
static void node_rna(StructRNA *srna)

View File

@ -247,6 +247,7 @@ static void window_manager_blend_read_after_liblink(BlendLibReader *reader, ID *
IDTypeInfo IDType_ID_WM = {
/*id_code*/ ID_WM,
/*id_filter*/ FILTER_ID_WM,
/*dependencies_id_types*/ FILTER_ID_SCE | FILTER_ID_WS,
/*main_listbase_index*/ INDEX_ID_WM,
/*struct_size*/ sizeof(wmWindowManager),
/*name*/ "WindowManager",