WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 351 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
65 changed files with 537 additions and 350 deletions
Showing only changes of commit 39eb3fe070 - 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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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",