BLF: Utility to Wrap a String into Multiple Lines #118436

Merged
Harley Acheson merged 7 commits from Harley/blender:WrapString into main 2024-02-21 01:19:14 +01:00
16 changed files with 390 additions and 326 deletions
Showing only changes of commit 402fa5229f - Show all commits

View File

@ -737,7 +737,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
if (cos_mi3 > 0.0f) {
const Spectrum A_tr = exp(mu_a / cos_theta(wtr) *
-(is_circular ?
2.0f * fabsf(cos(phi_tr - gamma_mt)) :
2.0f * fabsf(cosf(phi_tr - gamma_mt)) :
len(to_point(gamma_mt, b) - to_point(gamma_mtr, b))));
const Spectrum TR = T1 * R2 * scale2 * A_t * A_tr *

View File

@ -201,7 +201,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
cos_min_outgoing_angle = 1.0f;
}
else if ((bcone.theta_o + bcone.theta_e > M_PI_F) ||
(cos_theta_minus_theta_u > cos(bcone.theta_o + bcone.theta_e)))
(cos_theta_minus_theta_u > cosf(bcone.theta_o + bcone.theta_e)))
{
/* theta' = theta - theta_o - theta_u < theta_e */
kernel_assert(
@ -231,7 +231,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
float cos_max_outgoing_angle;
const float cos_theta_plus_theta_u = cos_theta * cos_theta_u - sin_theta * sin_theta_u;
if (bcone.theta_e - bcone.theta_o < 0 || cos_theta < 0 || cos_theta_u < 0 ||
cos_theta_plus_theta_u < cos(bcone.theta_e - bcone.theta_o))
cos_theta_plus_theta_u < cosf(bcone.theta_e - bcone.theta_o))
{
min_importance = 0.0f;
}

View File

@ -178,7 +178,7 @@ class AssetCatalogService {
*/
void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path);
AssetCatalogTree *get_catalog_tree();
AssetCatalogTree *get_catalog_tree() const;
/** Return true only if there are no catalogs known. */
bool is_empty() const;
@ -239,7 +239,7 @@ class AssetCatalogService {
* Construct an in-memory catalog definition file (CDF) from the currently known catalogs.
* This object can then be processed further before saving to disk. */
std::unique_ptr<AssetCatalogDefinitionFile> construct_cdf_in_memory(
const CatalogFilePath &file_path);
const CatalogFilePath &file_path) const;
/**
* Find a suitable path to write a CDF to.
@ -250,7 +250,7 @@ class AssetCatalogService {
static CatalogFilePath find_suitable_cdf_path_for_writing(
const CatalogFilePath &blend_file_path);
std::unique_ptr<AssetCatalogTree> read_into_tree();
std::unique_ptr<AssetCatalogTree> read_into_tree() const;
/**
* For every catalog, ensure that its parent path also has a known catalog.
@ -263,9 +263,9 @@ class AssetCatalogService {
void tag_all_catalogs_as_unsaved_changes();
/* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
AssetCatalogDefinitionFile *get_catalog_definition_file();
OwningAssetCatalogMap &get_catalogs();
OwningAssetCatalogMap &get_deleted_catalogs();
AssetCatalogDefinitionFile *get_catalog_definition_file() const;
OwningAssetCatalogMap &get_catalogs() const;
OwningAssetCatalogMap &get_deleted_catalogs() const;
};
/**

View File

@ -116,16 +116,16 @@ bool AssetCatalogService::is_empty() const
return catalog_collection_->catalogs_.is_empty();
}
OwningAssetCatalogMap &AssetCatalogService::get_catalogs()
OwningAssetCatalogMap &AssetCatalogService::get_catalogs() const
{
return catalog_collection_->catalogs_;
}
OwningAssetCatalogMap &AssetCatalogService::get_deleted_catalogs()
OwningAssetCatalogMap &AssetCatalogService::get_deleted_catalogs() const
{
return catalog_collection_->deleted_catalogs_;
}
AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file()
AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file() const
{
return catalog_collection_->catalog_definition_file_.get();
}
@ -560,7 +560,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
}
std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_in_memory(
const CatalogFilePath &file_path)
const CatalogFilePath &file_path) const
{
auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
cdf->file_path = file_path;
@ -572,12 +572,12 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_i
return cdf;
}
AssetCatalogTree *AssetCatalogService::get_catalog_tree()
AssetCatalogTree *AssetCatalogService::get_catalog_tree() const
{
return catalog_tree_.get();
}
std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree() const
{
auto tree = std::make_unique<AssetCatalogTree>();

View File

@ -16,7 +16,7 @@ namespace blender::asset_system {
AllAssetLibrary::AllAssetLibrary() : AssetLibrary(ASSET_LIBRARY_ALL) {}
void AllAssetLibrary::rebuild(const bool reload_catalogs)
void AllAssetLibrary::rebuild_catalogs_from_nested(const bool reload_nested_catalogs)
{
/* Start with empty catalog storage. Don't do this directly in #this.catalog_service to avoid
* race conditions. Rather build into a new service and replace the current one when done. */
@ -25,7 +25,7 @@ void AllAssetLibrary::rebuild(const bool reload_catalogs)
AssetLibrary::foreach_loaded(
[&](AssetLibrary &nested) {
if (reload_catalogs) {
if (reload_nested_catalogs) {
nested.catalog_service->reload_catalogs();
}
new_catalog_service->add_from_existing(*nested.catalog_service);
@ -37,7 +37,7 @@ void AllAssetLibrary::rebuild(const bool reload_catalogs)
void AllAssetLibrary::refresh_catalogs()
{
rebuild(/*reload_catalogs=*/true);
rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/true);
}
} // namespace blender::asset_system

View File

@ -18,7 +18,14 @@ class AllAssetLibrary : public AssetLibrary {
void refresh_catalogs() override;
void rebuild(const bool reload_catalogs);
/**
* Update the available catalogs and catalog tree from the nested asset libraries. Completely
* recreates the catalog service (invalidating pointers to the previous one).
*
* \param reload_nested_catalogs: Re-read catalog definitions of nested libraries from disk and
* merge them into the in-memory representations.
*/
void rebuild_catalogs_from_nested(bool reload_nested_catalogs);
};
} // namespace blender::asset_system

View File

@ -190,7 +190,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_current_file()
void AssetLibraryService::rebuild_all_library()
{
if (all_library_) {
all_library_->rebuild(false);
all_library_->rebuild_catalogs_from_nested(false);
}
}
@ -217,7 +217,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
all_library_ = std::make_unique<AllAssetLibrary>();
/* Don't reload catalogs on this initial read, they've just been loaded above. */
all_library_->rebuild(/*reload_catalogs=*/false);
all_library_->rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/false);
return all_library_.get();
}

View File

@ -49,7 +49,7 @@ class TestableAssetCatalogService : public AssetCatalogService {
return AssetCatalogService::get_catalog_definition_file();
}
OwningAssetCatalogMap &get_deleted_catalogs()
OwningAssetCatalogMap &get_deleted_catalogs() const
{
return AssetCatalogService::get_deleted_catalogs();
}

View File

@ -75,10 +75,10 @@ static float from_16dot16(FT_Fixed value)
/** \name Glyph Cache
* \{ */
static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, const float size)
static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font)
{
for (std::unique_ptr<GlyphCacheBLF> &gc : font->cache) {
if (gc->size == size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
if (gc->size == font->size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
(gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
(gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
(gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing))
@ -130,7 +130,7 @@ GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
{
font->glyph_cache_mutex.lock();
GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size);
GlyphCacheBLF *gc = blf_glyph_cache_find(font);
if (!gc) {
gc = blf_glyph_cache_new(font);
@ -1277,10 +1277,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return nullptr;
}
static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
GlyphCacheBLF *gc,
const uint charcode,
uint8_t subpixel)
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode, uint8_t subpixel)
{
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode, subpixel);
if (g) {
@ -1306,11 +1303,6 @@ static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
return g;
}
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode)
{
return blf_glyph_ensure_ex(font, gc, charcode, 0);
}
#ifdef BLF_SUBPIXEL_AA
GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x)
{
@ -1328,7 +1320,7 @@ GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *
const uint8_t subpixel = uint8_t(pen_x & ((font->size > 16.0f) ? 32L : 48L));
if (g->subpixel != subpixel) {
g = blf_glyph_ensure_ex(font, gc, g->c, subpixel);
g = blf_glyph_ensure(font, gc, g->c, subpixel);
}
return g;
}

View File

@ -182,7 +182,10 @@ void blf_glyph_cache_clear(struct FontBLF *font);
/**
* Create (or load from cache) a fully-rendered bitmap glyph.
*/
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font,
struct GlyphCacheBLF *gc,
uint charcode,
uint8_t subpixel = 0);
#ifdef BLF_SUBPIXEL_AA
struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font,

View File

@ -25,8 +25,8 @@ struct LightProbeSample {
*/
LightProbeSample lightprobe_load(vec3 P, vec3 Ng, vec3 V)
{
/* TODO: Dependency hell */
float noise = 0.0;
float noise = interlieved_gradient_noise(UTIL_TEXEL, 0.0, 0.0);
noise = fract(noise + sampling_rng_1D_get(SAMPLING_LIGHTPROBE));
LightProbeSample result;
result.volume_irradiance = lightprobe_irradiance_sample(P, V, Ng);

View File

@ -2637,6 +2637,32 @@ static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wco
/** \} */
/* -------------------------------------------------------------------- */
/** \name Widget Emboss Helper
*
* Emboss is an (optional) shadow shown under the bottom edge of buttons. For
* vertically-aligned stacks of buttons it should only be shown under the bottom one.
* \{ */
static bool draw_emboss(const uiBut *but)
{
if (but->drawflag & UI_BUT_ALIGN_DOWN) {
return false;
}
if (but->type == UI_BTYPE_TAB &&
(BLI_rctf_size_y(&but->block->rect) > BLI_rctf_size_x(&but->block->rect)) &&
!(but->next == nullptr || but->next->type == UI_BTYPE_SEPR))
{
/* Vertical tabs, emboss at end and before separators. */
return false;
}
return true;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Widget Types
* \{ */
@ -3403,7 +3429,8 @@ static void ui_draw_separator(const uiWidgetColors *wcol, uiBut *but, const rcti
#define NUM_BUT_PADDING_FACTOR 0.425f
static void widget_numbut_draw(uiWidgetColors *wcol,
static void widget_numbut_draw(const uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const float zoom,
const uiWidgetStateInfo *state,
@ -3493,12 +3520,12 @@ static void widget_numbut_draw(uiWidgetColors *wcol,
/* outline */
wtb.draw_inner = false;
wtb.draw_emboss = roundboxalign & (UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
wtb.draw_emboss = draw_emboss(but);
widgetbase_draw(&wtb, wcol);
}
else {
/* inner and outline */
wtb.draw_emboss = roundboxalign & (UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
wtb.draw_emboss = draw_emboss(but);
widgetbase_draw(&wtb, wcol);
}
@ -3510,13 +3537,14 @@ static void widget_numbut_draw(uiWidgetColors *wcol,
}
}
static void widget_numbut(uiWidgetColors *wcol,
static void widget_numbut(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, false);
}
static void widget_menubut(uiWidgetColors *wcol,
@ -3567,14 +3595,14 @@ static void widget_menubut_embossn(const uiBut * /*but*/,
/**
* Draw number buttons still with triangles when field is not embossed
*/
static void widget_numbut_embossn(const uiBut * /*but*/,
static void widget_numbut_embossn(const uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, true);
widget_numbut_draw(but, wcol, rect, zoom, state, roundboxalign, true);
}
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
@ -4414,8 +4442,7 @@ static void widget_box(uiBut *but,
const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
wtb.draw_emboss = roundboxalign & (UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
wtb.draw_emboss = draw_emboss(but);
widgetbase_draw(&wtb, wcol);
copy_v3_v3_uchar(wcol->inner, old_col);
@ -4451,7 +4478,8 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int /*state*/ int
}
#endif
static void widget_roundbut_exec(uiWidgetColors *wcol,
static void widget_roundbut_exec(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
@ -4469,12 +4497,12 @@ static void widget_roundbut_exec(uiWidgetColors *wcol,
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
wtb.draw_emboss = roundboxalign & (UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
wtb.draw_emboss = draw_emboss(but);
widgetbase_draw(&wtb, wcol);
}
static void widget_tab(uiWidgetColors *wcol,
static void widget_tab(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
@ -4509,6 +4537,7 @@ static void widget_tab(uiWidgetColors *wcol,
#ifdef USE_TAB_SHADED_HIGHLIGHT
wtb.draw_outline = 0;
#endif
wtb.draw_emboss = draw_emboss(but);
widgetbase_draw(&wtb, wcol);
/* We are drawing on top of widget bases. Flush cache. */
@ -4603,7 +4632,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_NUMBER:
wt.wcol_theme = &btheme->tui.wcol_num;
wt.draw = widget_numbut;
wt.custom = widget_numbut;
break;
case UI_WTYPE_SLIDER:
@ -4614,17 +4643,17 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_EXEC:
wt.wcol_theme = &btheme->tui.wcol_tool;
wt.draw = widget_roundbut_exec;
wt.custom = widget_roundbut_exec;
break;
case UI_WTYPE_TOOLBAR_ITEM:
wt.wcol_theme = &btheme->tui.wcol_toolbar_item;
wt.draw = widget_roundbut_exec;
wt.custom = widget_roundbut_exec;
break;
case UI_WTYPE_TAB:
wt.wcol_theme = &btheme->tui.wcol_tab;
wt.draw = widget_tab;
wt.custom = widget_tab;
break;
case UI_WTYPE_TOOLTIP:

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ static void add_huff_table(j_decompress_ptr dinfo,
memcpy((*htblptr)->huffval, val, min_zz(sizeof((*htblptr)->huffval), val_size));
/* Initialize sent_table false so table will be written to JPEG file. */
(*htblptr)->sent_table = false;
(*htblptr)->sent_table = FALSE;
}
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
@ -226,7 +226,7 @@ static int Decode_JPEG(uchar *inBuffer, uchar *outBuffer, uint width, uint heigh
dinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&dinfo);
jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize);
jpeg_read_header(&dinfo, true);
jpeg_read_header(&dinfo, TRUE);
if (dinfo.dc_huff_tbl_ptrs[0] == nullptr) {
std_huff_tables(&dinfo);
}
@ -250,7 +250,7 @@ static int Decode_JPEG(uchar *inBuffer, uchar *outBuffer, uint width, uint heigh
jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize - numbytes);
numbytes = 0;
jpeg_read_header(&dinfo, true);
jpeg_read_header(&dinfo, TRUE);
if (dinfo.dc_huff_tbl_ptrs[0] == nullptr) {
std_huff_tables(&dinfo);
}
@ -286,21 +286,21 @@ static void Compress_JPEG(
jpeg_set_defaults(&cinfo);
jpeg_set_colorspace(&cinfo, JCS_YCbCr);
jpeg_set_quality(&cinfo, quality, true);
jpeg_set_quality(&cinfo, quality, TRUE);
cinfo.dc_huff_tbl_ptrs[0]->sent_table = true;
cinfo.dc_huff_tbl_ptrs[1]->sent_table = true;
cinfo.ac_huff_tbl_ptrs[0]->sent_table = true;
cinfo.ac_huff_tbl_ptrs[1]->sent_table = true;
cinfo.dc_huff_tbl_ptrs[0]->sent_table = TRUE;
cinfo.dc_huff_tbl_ptrs[1]->sent_table = TRUE;
cinfo.ac_huff_tbl_ptrs[0]->sent_table = TRUE;
cinfo.ac_huff_tbl_ptrs[1]->sent_table = TRUE;
cinfo.comp_info[0].component_id = 0;
cinfo.comp_info[0].v_samp_factor = 1;
cinfo.comp_info[1].component_id = 1;
cinfo.comp_info[2].component_id = 2;
cinfo.write_JFIF_header = false;
cinfo.write_JFIF_header = FALSE;
jpeg_start_compress(&cinfo, false);
jpeg_start_compress(&cinfo, FALSE);
int i = 0;
marker[i++] = 'A';
@ -469,7 +469,7 @@ static void jpegmemdestmgr_init_destination(j_compress_ptr cinfo)
static boolean jpegmemdestmgr_empty_output_buffer(j_compress_ptr cinfo)
{
(void)cinfo; /* unused */
return true;
return TRUE;
}
static void jpegmemdestmgr_term_destination(j_compress_ptr cinfo)
@ -514,7 +514,7 @@ static boolean jpegmemsrcmgr_fill_input_buffer(j_decompress_ptr dinfo)
dinfo->src->next_input_byte = buf;
dinfo->src->bytes_in_buffer = 2;
return true;
return TRUE;
}
static void jpegmemsrcmgr_skip_input_data(j_decompress_ptr dinfo, long skip_count)

View File

@ -904,6 +904,12 @@ const EnumPropertyItem *RNA_node_tree_interface_socket_menu_itemf(bContext * /*C
return RNA_node_enum_definition_itemf(*data->enum_items, r_free);
}
static void rna_NodeTreeInterfaceSocket_idname_set(PointerRNA *ptr, const char *value)
{
bNodeTreeInterfaceSocket &socket = *static_cast<bNodeTreeInterfaceSocket *>(ptr->data);
socket.set_socket_type(value);
}
#else
static void rna_def_node_interface_item(BlenderRNA *brna)
@ -1057,6 +1063,8 @@ static void rna_def_node_interface_socket(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, nullptr, "socket_type");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Socket Type Name", "Name of the socket type");
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_NodeTreeInterfaceSocket_idname_set");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeTreeInterfaceItem_update");
func = RNA_def_function(srna, "draw", nullptr);
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);

View File

@ -6,8 +6,18 @@
#include <fmt/format.h>
#include "NOD_rna_define.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
namespace blender::nodes::node_geo_remove_attribute_cc {
enum class PatternMode {
Exact,
Wildcard,
};
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
@ -15,22 +25,44 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry").propagate_all();
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "pattern_mode", UI_ITEM_NONE, "", ICON_NONE);
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const std::string name = params.extract_input<std::string>("Name");
if (name.empty()) {
const std::string pattern = params.extract_input<std::string>("Name");
if (pattern.empty()) {
params.set_output("Geometry", std::move(geometry_set));
return;
}
if (!bke::allow_procedural_attribute_access(name)) {
params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
params.set_output("Geometry", std::move(geometry_set));
return;
const bNode &node = params.node();
PatternMode pattern_mode = PatternMode(node.custom1);
if (pattern_mode == PatternMode::Wildcard) {
const int wildcard_count = Span(pattern.c_str(), pattern.size()).count('*');
if (wildcard_count == 0) {
pattern_mode = PatternMode::Exact;
}
else if (wildcard_count >= 2) {
params.error_message_add(NodeWarningType::Info,
TIP_("Only one * is supported in the pattern"));
params.set_output("Geometry", std::move(geometry_set));
return;
}
}
std::atomic<bool> attribute_exists = false;
std::atomic<bool> cannot_delete = false;
StringRef wildcard_prefix;
StringRef wildcard_suffix;
if (pattern_mode == PatternMode::Wildcard) {
const int wildcard_index = pattern.find('*');
wildcard_prefix = StringRef(pattern).substr(0, wildcard_index);
wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1);
}
Set<std::string> removed_attributes;
Set<std::string> failed_attributes;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
@ -38,42 +70,103 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponent::Type::Curve,
GeometryComponent::Type::Instance})
{
if (geometry_set.has(type)) {
/* First check if the attribute exists before getting write access,
* to avoid potentially expensive unnecessary copies. */
const GeometryComponent &read_only_component = *geometry_set.get_component(type);
if (read_only_component.attributes()->contains(name)) {
attribute_exists = true;
if (!geometry_set.has(type)) {
continue;
}
/* First check if the attribute exists before getting write access,
* to avoid potentially expensive unnecessary copies. */
const GeometryComponent &read_only_component = *geometry_set.get_component(type);
Vector<std::string> attributes_to_remove;
switch (pattern_mode) {
case PatternMode::Exact: {
if (read_only_component.attributes()->contains(pattern)) {
attributes_to_remove.append(pattern);
}
break;
}
else {
case PatternMode::Wildcard: {
read_only_component.attributes()->for_all(
[&](const blender::bke::AttributeIDRef &id,
const blender::bke::AttributeMetaData /*meta_data*/) {
if (id.is_anonymous()) {
return true;
}
const StringRef attribute_name = id.name();
if (attribute_name.startswith(wildcard_prefix) &&
attribute_name.endswith(wildcard_suffix))
{
attributes_to_remove.append(attribute_name);
}
return true;
});
break;
}
}
if (attributes_to_remove.is_empty()) {
break;
}
GeometryComponent &component = geometry_set.get_component_for_write(type);
for (const StringRef attribute_name : attributes_to_remove) {
if (!bke::allow_procedural_attribute_access(attribute_name)) {
continue;
}
GeometryComponent &component = geometry_set.get_component_for_write(type);
if (!component.attributes_for_write()->remove(name)) {
cannot_delete = true;
if (component.attributes_for_write()->remove(attribute_name)) {
removed_attributes.add(attribute_name);
}
else {
failed_attributes.add(attribute_name);
}
}
}
});
if (attribute_exists && !cannot_delete) {
params.used_named_attribute(name, NamedAttributeUsage::Remove);
for (const StringRef attribute_name : removed_attributes) {
params.used_named_attribute(attribute_name, NamedAttributeUsage::Remove);
}
if (!attribute_exists) {
const std::string message = fmt::format(TIP_("Attribute does not exist: \"{}\""), name);
if (!failed_attributes.is_empty()) {
Vector<std::string> quoted_attribute_names;
for (const StringRef attribute_name : failed_attributes) {
quoted_attribute_names.append(fmt::format("\"{}\"", attribute_name));
}
const std::string message = fmt::format(TIP_("Cannot remove built-in attributes: {}"),
fmt::join(quoted_attribute_names, ", "));
params.error_message_add(NodeWarningType::Warning, message);
}
if (cannot_delete) {
const std::string message = fmt::format(TIP_("Cannot delete built-in attribute: \"{}\""),
name);
else if (removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) {
const std::string message = fmt::format(TIP_("Attribute does not exist: \"{}\""), pattern);
params.error_message_add(NodeWarningType::Warning, message);
}
params.set_output("Geometry", std::move(geometry_set));
}
static void node_rna(StructRNA *srna)
{
static const EnumPropertyItem pattern_mode_items[] = {
{int(PatternMode::Exact),
"EXACT",
0,
"Exact",
"Remove the one attribute with the given name"},
{int(PatternMode::Wildcard),
"WILDCARD",
0,
"Wildcard",
"Remove all attributes that match the pattern which is allowed to contain a single "
"wildcard (*)."},
{0, nullptr, 0, nullptr, nullptr},
};
RNA_def_node_enum(srna,
"pattern_mode",
"Pattern Mode",
"How the attributes to remove are chosen",
pattern_mode_items,
NOD_inline_enum_accessors(custom1));
}
static void node_register()
{
static bNodeType ntype;
@ -81,9 +174,12 @@ static void node_register()
geo_node_type_base(
&ntype, GEO_NODE_REMOVE_ATTRIBUTE, "Remove Named Attribute", NODE_CLASS_ATTRIBUTE);
ntype.declare = node_declare;
ntype.draw_buttons = node_layout;
bke::node_type_size(&ntype, 170, 100, 700);
ntype.geometry_node_execute = node_geo_exec;
nodeRegisterType(&ntype);
node_rna(ntype.rna_ext.srna);
}
NOD_REGISTER_NODE(node_register)