diff options
Diffstat (limited to 'source/blender')
560 files changed, 14983 insertions, 10230 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 78252bdb08b..fa8e764139d 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -43,6 +43,8 @@ void BLF_exit(void); void BLF_cache_clear(void); +void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void)); + /* Loads a font, or returns an already loaded font and increments its reference count. */ int BLF_load(const char *name) ATTR_NONNULL(); int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL(); @@ -63,7 +65,7 @@ void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size); void BLF_aspect(int fontid, float x, float y, float z); void BLF_position(int fontid, float x, float y, float z); -void BLF_size(int fontid, int size, int dpi); +void BLF_size(int fontid, float size, int dpi); /* goal: small but useful color API */ void BLF_color4ubv(int fontid, const unsigned char rgba[4]); @@ -250,6 +252,7 @@ void BLF_thumb_preview(const char *filename, /* blf_default.c */ void BLF_default_dpi(int dpi); +void BLF_default_size(int size); void BLF_default_set(int fontid); int BLF_default(void); /* get default font ID so we can pass it to other functions */ /* Draw the string using the default font, size and dpi. */ diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 59a9072de57..cc6e298b322 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -23,7 +23,6 @@ set(INC ../blenkernel ../blenlib ../blentranslation - ../editors/include ../gpu ../imbuf ../makesdna diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 34ddb6f22d2..d6773916abd 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -363,7 +363,7 @@ void BLF_position(int fontid, float x, float y, float z) } } -void BLF_size(int fontid, int size, int dpi) +void BLF_size(int fontid, float size, int dpi) { FontBLF *font = blf_get(fontid); @@ -910,7 +910,7 @@ void BLF_state_print(int fontid) if (font) { printf("fontid %d %p\n", fontid, (void *)font); printf(" name: '%s'\n", font->name); - printf(" size: %u\n", font->size); + printf(" size: %f\n", font->size); printf(" dpi: %u\n", font->dpi); printf(" pos: %.6f %.6f %.6f\n", UNPACK3(font->pos)); printf(" aspect: (%d) %.6f %.6f %.6f\n", diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c index 2bac0bf8904..57eeaa6768d 100644 --- a/source/blender/blenfont/intern/blf_default.c +++ b/source/blender/blenfont/intern/blf_default.c @@ -29,8 +29,6 @@ #include "BLF_api.h" -#include "UI_interface.h" - #include "blf_internal.h" /* call BLF_default_set first! */ @@ -39,12 +37,19 @@ /* Default size and dpi, for BLF_draw_default. */ static int global_font_default = -1; static int global_font_dpi = 72; +/* Keep in sync with `UI_style_get()->widgetlabel.points` */ +static int global_font_size = 11; void BLF_default_dpi(int dpi) { global_font_dpi = dpi; } +void BLF_default_size(int size) +{ + global_font_size = size; +} + void BLF_default_set(int fontid) { if ((fontid == -1) || blf_font_id_is_valid(fontid)) { @@ -62,8 +67,7 @@ int BLF_set_default(void) { ASSERT_DEFAULT_SET; - const uiStyle *style = UI_style_get(); - BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); + BLF_size(global_font_default, global_font_size, global_font_dpi); return global_font_default; } @@ -71,9 +75,7 @@ int BLF_set_default(void) void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len) { ASSERT_DEFAULT_SET; - - const uiStyle *style = UI_style_get(); - BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); + BLF_size(global_font_default, global_font_size, global_font_dpi); BLF_position(global_font_default, x, y, z); BLF_draw(global_font_default, str, str_len); } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 27478bd7f8e..c81d18ba7de 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -34,6 +34,7 @@ #include FT_FREETYPE_H #include FT_GLYPH_H +#include FT_ADVANCES_H /* For FT_Get_Advance */ #include "MEM_guardedalloc.h" @@ -49,8 +50,6 @@ #include "BLF_api.h" -#include "UI_interface.h" - #include "GPU_batch.h" #include "GPU_matrix.h" @@ -71,6 +70,9 @@ static FT_Library ft_lib; static SpinLock ft_lib_mutex; static SpinLock blf_glyph_cache_mutex; +/* May be set to #UI_widgetbase_draw_cache_flush. */ +static void (*blf_draw_cache_flush)(void) = NULL; + /* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ @@ -254,10 +256,10 @@ void blf_batch_draw(void) GPU_blend(GPU_BLEND_ALPHA); -#ifndef BLF_STANDALONE /* We need to flush widget base first to ensure correct ordering. */ - UI_widgetbase_draw_cache_flush(); -#endif + if (blf_draw_cache_flush != NULL) { + blf_draw_cache_flush(); + } GPUTexture *texture = blf_batch_cache_texture_load(); GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len); @@ -297,44 +299,27 @@ static void blf_batch_draw_end(void) * characters. */ -BLI_INLINE GlyphBLF *blf_utf8_next_fast( - FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p, uint *r_c) +BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step( + FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p) { - GlyphBLF *g; - if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) { - g = (gc->glyph_ascii_table)[*r_c]; - if (UNLIKELY(g == NULL)) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); - gc->glyph_ascii_table[*r_c] = g; - } - (*i_p)++; - } - else { - *r_c = BLI_str_utf8_as_unicode_step(str, str_len, i_p); - g = blf_glyph_search(gc, *r_c); - if (UNLIKELY(g == NULL)) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); - } - } - return g; + uint charcode = BLI_str_utf8_as_unicode_step(str, str_len, i_p); + /* Invalid unicode sequences return the byte value, stepping forward one. + * This allows `latin1` to display (which is sometimes used for file-paths). */ + BLI_assert(charcode != BLI_UTF8_ERR); + return blf_glyph_ensure(font, gc, charcode); } -BLI_INLINE void blf_kerning_step_fast(FontBLF *font, - const GlyphBLF *g_prev, - const GlyphBLF *g, - const uint c_prev, - const uint c, - int *pen_x_p) +BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g) { if (!FT_HAS_KERNING(font->face) || g_prev == NULL) { - return; + return 0; } FT_Vector delta = {KERNING_ENTRY_UNSET}; /* Get unscaled kerning value from our cache if ASCII. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - delta.x = font->kerning_cache->ascii_table[c][c_prev]; + if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) { + delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c]; } /* If not ASCII or not found in cache, ask FreeType for kerning. */ @@ -344,14 +329,16 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, } /* If ASCII we save this value to our cache for quicker access next time. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x; + if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) { + font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x; } if (delta.x != 0) { /* Convert unscaled design units to pixels and move pen. */ - *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x); + return blf_unscaled_F26Dot6_to_pixels(font, delta.x); } + + return 0; } /** \} */ @@ -367,7 +354,6 @@ static void blf_font_draw_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0; @@ -380,22 +366,18 @@ static void blf_font_draw_ex(FontBLF *font, blf_batch_draw_begin(font); while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); /* do not return this loop if clipped, we want every character tested */ - blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); + blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y); pen_x += g->advance_i; g_prev = g; - c_prev = c; } blf_batch_draw_end(); @@ -415,7 +397,6 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct /* use fixed column width, but an utf8 character may occupy multiple columns */ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth) { - unsigned int c; GlyphBLF *g; int col, columns = 0; int pen_x = 0, pen_y = 0; @@ -426,19 +407,15 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int blf_batch_draw_begin(font); while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - /* do not return this loop if clipped, we want every character tested */ - blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); + blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y); - col = BLI_wcwidth((char32_t)c); + col = BLI_wcwidth((char32_t)g->c); if (col < 0) { col = 1; } @@ -467,7 +444,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = (int)font->pos[0]; int pen_y_basis = (int)font->pos[1] + pen_y; @@ -483,15 +459,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* another buffer specific call for color conversion */ while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); chx = pen_x + ((int)g->pos[0]); chy = pen_y_basis + g->dims[1]; @@ -588,7 +561,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, pen_x += g->advance_i; g_prev = g; - c_prev = c; } if (r_info) { @@ -610,38 +582,29 @@ void blf_font_draw_buffer(FontBLF *font, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Text Evaluation: Width to Sting Length +/** \name Text Evaluation: Width to String Length * * Use to implement exported functions: * - #BLF_width_to_strlen * - #BLF_width_to_rstrlen * \{ */ -static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, - const uint c_prev, - const uint c, - GlyphBLF *g_prev, - GlyphBLF *g, - int *pen_x, - const int width_i) +static bool blf_font_width_to_strlen_glyph_process( + FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, int *pen_x, const int width_i) { - if (UNLIKELY(c == BLI_UTF8_ERR)) { - return true; /* break the calling loop. */ - } if (UNLIKELY(g == NULL)) { return false; /* continue the calling loop. */ } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, pen_x); - + *pen_x += blf_kerning(font, g_prev, g); *pen_x += g->advance_i; + /* When true, break the calling loop. */ return (*pen_x >= width_i); } size_t blf_font_width_to_strlen( FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; int pen_x, width_new; size_t i, i_prev; @@ -649,11 +612,11 @@ size_t blf_font_width_to_strlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < str_len) && str[i]; - i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL; (i < str_len) && str[i]; + i_prev = i, width_new = pen_x, g_prev = g) { + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) { break; } } @@ -669,7 +632,6 @@ size_t blf_font_width_to_strlen( size_t blf_font_width_to_rstrlen( FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; int pen_x, width_new; size_t i, i_prev, i_tmp; @@ -685,19 +647,19 @@ size_t blf_font_width_to_rstrlen( i_prev = (size_t)(s_prev - str); i_tmp = i; - g = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp); for (width_new = pen_x = 0; (s != NULL); - i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { + i = i_prev, s = s_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { s_prev = BLI_str_find_prev_char_utf8(s, str); i_prev = (size_t)(s_prev - str); if (s_prev != NULL) { i_tmp = i_prev; - g_prev = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c_prev); + g_prev = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp); BLI_assert(i_tmp == i); } - if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) { break; } } @@ -724,7 +686,6 @@ static void blf_font_boundbox_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0; @@ -736,15 +697,12 @@ static void blf_font_boundbox_ex(FontBLF *font, box->ymax = -32000.0f; while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); gbox.xmin = (float)pen_x; gbox.xmax = (float)pen_x + g->advance; @@ -767,7 +725,6 @@ static void blf_font_boundbox_ex(FontBLF *font, pen_x += g->advance_i; g_prev = g; - c_prev = c; } if (box->xmin > box->xmax) { @@ -869,22 +826,7 @@ float blf_font_height(FontBLF *font, float blf_font_fixed_width(FontBLF *font) { - const unsigned int c = ' '; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF *g = blf_glyph_search(gc, c); - if (!g) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c); - - /* if we don't find the glyph. */ - if (!g) { - blf_glyph_cache_release(font); - return 0.0f; - } - } - - blf_glyph_cache_release(font); - return g->advance; + return (float)font->fixed_width; } static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, @@ -896,7 +838,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0, i_curr; @@ -909,15 +850,12 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, while ((i < str_len) && str[i]) { i_curr = i; - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); gbox.xmin = pen_x; gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); @@ -931,7 +869,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, } g_prev = g; - c_prev = c; } if (r_info) { @@ -978,7 +915,6 @@ static void blf_font_wrap_apply(FontBLF *font, void *userdata), void *userdata) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0, pen_y = 0; size_t i = 0; @@ -999,15 +935,12 @@ static void blf_font_wrap_apply(FontBLF *font, size_t i_curr = i; bool do_draw = false; - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); /** * Implementation Detail (utf8). @@ -1045,16 +978,14 @@ static void blf_font_wrap_apply(FontBLF *font, wrap.start = wrap.last[0]; i = wrap.last[1]; pen_x = 0; - pen_y -= gc->glyph_height_max; + pen_y -= blf_font_height_max(font); g_prev = NULL; - c_prev = BLI_UTF8_ERR; lines += 1; continue; } pen_x = pen_x_next; g_prev = g; - c_prev = c; } // printf("done! lines: %d, width, %d\n", lines, pen_x_next); @@ -1170,45 +1101,41 @@ int blf_font_count_missing_chars(FontBLF *font, int blf_font_height_max(FontBLF *font) { int height_max; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - height_max = gc->glyph_height_max; - - blf_glyph_cache_release(font); - return height_max; + if (FT_IS_SCALABLE(font->face)) { + height_max = (int)((float)(font->face->ascender - font->face->descender) * + (((float)font->face->size->metrics.y_ppem) / + ((float)font->face->units_per_EM))); + } + else { + height_max = (int)(((float)font->face->size->metrics.height) / 64.0f); + } + /* can happen with size 1 fonts */ + return MAX2(height_max, 1); } int blf_font_width_max(FontBLF *font) { int width_max; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - width_max = gc->glyph_width_max; - - blf_glyph_cache_release(font); - return width_max; + if (FT_IS_SCALABLE(font->face)) { + width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) * + (((float)font->face->size->metrics.x_ppem) / + ((float)font->face->units_per_EM))); + } + else { + width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f); + } + /* can happen with size 1 fonts */ + return MAX2(width_max, 1); } float blf_font_descender(FontBLF *font) { - float descender; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - descender = gc->descender; - - blf_glyph_cache_release(font); - return descender; + return ((float)font->face->size->metrics.descender) / 64.0f; } float blf_font_ascender(FontBLF *font) { - float ascender; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - ascender = gc->ascender; - - blf_glyph_cache_release(font); - return ascender; + return ((float)font->face->size->metrics.ascender) / 64.0f; } char *blf_display_name(FontBLF *font) @@ -1241,6 +1168,14 @@ void blf_font_exit(void) blf_batch_draw_exit(); } +/** + * Optional cache flushing function, called before #blf_batch_draw. + */ +void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void)) +{ + blf_draw_cache_flush = cache_flush_fn; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1415,19 +1350,24 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ -void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) +void blf_font_size(FontBLF *font, float size, unsigned int dpi) { blf_glyph_cache_acquire(font); + /* FreeType uses fixed-point integers in 64ths. */ + FT_F26Dot6 ft_size = lroundf(size * 64.0f); + /* Adjust our size to be on even 64ths. */ + size = (float)ft_size / 64.0f; + GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi); if (gc && (font->size == size && font->dpi == dpi)) { /* Optimization: do not call FT_Set_Char_Size if size did not change. */ } else { - const FT_Error err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); + const FT_Error err = FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi); if (err) { /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); + printf("The current font don't support the size, %f and dpi, %u\n", size, dpi); } else { font->size = size; @@ -1439,6 +1379,22 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) } blf_glyph_cache_release(font); + + /* Set fixed-width size for monospaced output. */ + FT_UInt gindex = FT_Get_Char_Index(font->face, U'0'); + if (gindex) { + FT_Fixed advance = 0; + FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); + /* Use CSS 'ch unit' width, advance of zero character. */ + font->fixed_width = (int)(advance >> 16); + } + else { + /* Font does not contain "0" so use CSS fallback of 1/2 of em. */ + font->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6); + } + if (font->fixed_width < 1) { + font->fixed_width = 1; + } } /** \} */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 6cdf5fc5996..5f14ef433e9 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -55,27 +55,47 @@ #include "BLI_math_vector.h" #include "BLI_strict_flags.h" -GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + +/** + * Convert a floating point value to a FreeType 16.16 fixed point value. + */ +static FT_Fixed to_16dot16(double val) { - GlyphCacheBLF *p; + return (FT_Fixed)(lround(val * 65536.0)); +} - p = (GlyphCacheBLF *)font->cache.first; - while (p) { - if (p->size == size && p->dpi == dpi && (p->bold == ((font->flags & BLF_BOLD) != 0)) && - (p->italic == ((font->flags & BLF_ITALIC) != 0))) { - return p; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Cache + * \{ */ + +/** + * Find a glyph cache that matches a size, DPI & styles. + */ +GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) +{ + GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; + while (gc) { + if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) && + (gc->italic == ((font->flags & BLF_ITALIC) != 0))) { + return gc; } - p = p->next; + gc = gc->next; } return NULL; } -/* Create a new glyph cache for the current size, dpi, bold, italic. */ +/** + * Create a new glyph cache for the current size, DPI & styles. + */ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) { - GlyphCacheBLF *gc; + GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); - gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); gc->next = NULL; gc->prev = NULL; gc->size = font->size; @@ -86,27 +106,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); - gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f; - gc->descender = ((float)font->face->size->metrics.descender) / 64.0f; - - if (FT_IS_SCALABLE(font->face)) { - gc->glyph_width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) * - (((float)font->face->size->metrics.x_ppem) / - ((float)font->face->units_per_EM))); - - gc->glyph_height_max = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) * - (((float)font->face->size->metrics.y_ppem) / - ((float)font->face->units_per_EM))); - } - else { - gc->glyph_width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f); - gc->glyph_height_max = (int)(((float)font->face->size->metrics.height) / 64.0f); - } - - /* can happen with size 1 fonts */ - CLAMP_MIN(gc->glyph_width_max, 1); - CLAMP_MIN(gc->glyph_height_max, 1); - BLI_addhead(&font->cache, gc); return gc; } @@ -159,59 +158,95 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) MEM_freeN(gc); } -GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) +/** + * Try to find a glyph in cache. + * + * \return NULL if not found. + */ +static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode) { - GlyphBLF *p; - unsigned int key; - - key = blf_hash(c); - p = gc->bucket[key].first; - while (p) { - if (p->c == c) { - return p; + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + return gc->glyph_ascii_table[charcode]; + } + + GlyphBLF *g = gc->bucket[blf_hash(charcode)].first; + while (g) { + if (g->c == charcode) { + return g; } - p = p->next; + g = g->next; } return NULL; } -GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c) +/** + * Add a rendered glyph to a cache. + */ +static GlyphBLF *blf_glyph_cache_add_glyph( + FontBLF *font, GlyphCacheBLF *gc, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index) { - FT_GlyphSlot slot; - GlyphBLF *g; - FT_Error err; - FT_Bitmap bitmap, tempbitmap; + GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get"); + g->c = charcode; + g->idx = glyph_index; + g->advance = ((float)glyph->advance.x) / 64.0f; + g->advance_i = (int)g->advance; + g->pos[0] = glyph->bitmap_left; + g->pos[1] = glyph->bitmap_top; + g->dims[0] = (int)glyph->bitmap.width; + g->dims[1] = (int)glyph->bitmap.rows; + g->pitch = glyph->bitmap.pitch; + FT_BBox bbox; - unsigned int key; + FT_Outline_Get_CBox(&(glyph->outline), &bbox); + g->box.xmin = ((float)bbox.xMin) / 64.0f; + g->box.xmax = ((float)bbox.xMax) / 64.0f; + g->box.ymin = ((float)bbox.yMin) / 64.0f; + g->box.ymax = ((float)bbox.yMax) / 64.0f; - g = blf_glyph_search(gc, c); - if (g) { - return g; + const int buffer_size = (int)(glyph->bitmap.width * glyph->bitmap.rows); + if (buffer_size != 0) { + if (font->flags & BLF_MONOCHROME) { + /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range. */ + for (int i = 0; i < buffer_size; i++) { + glyph->bitmap.buffer[i] = glyph->bitmap.buffer[i] ? 255 : 0; + } + } + g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); + memcpy(g->bitmap, glyph->bitmap.buffer, (size_t)buffer_size); } - /* glyphs are dynamically created as needed by font rendering. this means that - * to make font rendering thread safe we have to do locking here. note that this - * must be a lock for the whole library and not just per font, because the font - * renderer uses a shared buffer internally */ - BLI_spin_lock(font->ft_lib_mutex); - - /* search again after locking */ - g = blf_glyph_search(gc, c); - if (g) { - BLI_spin_unlock(font->ft_lib_mutex); - return g; + unsigned int key = blf_hash(g->c); + BLI_addhead(&(gc->bucket[key]), g); + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + gc->glyph_ascii_table[charcode] = g; } + return g; +} + +/** + * Return a glyph index from `charcode`. Not found returns zero, which is a valid + * printable character (`.notdef` or `tofu`). Font is allowed to change here. + */ +static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode) +{ + FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode); + /* TODO: If not found in this font, check others, update font pointer. */ + return glyph_index; +} + +/** + * Load a glyph into the glyph slot of a font's face object. + */ +static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index) +{ int load_flags; - int render_mode; if (font->flags & BLF_MONOCHROME) { load_flags = FT_LOAD_TARGET_MONO; - render_mode = FT_RENDER_MODE_MONO; } else { load_flags = FT_LOAD_NO_BITMAP; - render_mode = FT_RENDER_MODE_NORMAL; if (font->flags & BLF_HINTING_NONE) { load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING; } @@ -228,104 +263,222 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un } } - err = FT_Load_Glyph(font->face, (FT_UInt)index, load_flags); - - /* Do not oblique a font that is designed to be italic! */ - if (((font->flags & BLF_ITALIC) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_ITALIC) && - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* For (fake) italic: a shear transform with a 6 degree angle. */ - FT_Matrix transform; - transform.xx = 0x10000L; - transform.yx = 0x00000L; - transform.xy = 0x03000L; - transform.yy = 0x10000L; - FT_Outline_Transform(&font->face->glyph->outline, &transform); - } - - /* Do not embolden an already bold font! */ - if (((font->flags & BLF_BOLD) != 0) && - !(font->face->style_flags & FT_STYLE_FLAG_BOLD) & - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* Strengthen the width more than the height. */ - const FT_Pos extra_x = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.x_scale) / - 14; - const FT_Pos extra_y = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.y_scale) / - 28; - FT_Outline_EmboldenXY(&font->face->glyph->outline, extra_x, extra_y); - if ((font->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) == 0) { - /* Need to increase advance, but not for fixed-width fonts. */ - font->face->glyph->advance.x += (FT_Pos)(((float)extra_x) * 1.05f); - font->face->glyph->advance.y += extra_y; - } - else { - /* Widened fixed-pitch font gets a nudge left. */ - FT_Outline_Translate(&font->face->glyph->outline, (extra_x / -2), 0); - } + if (FT_Load_Glyph(font->face, glyph_index, load_flags) == 0) { + return font->face->glyph; + } + return NULL; +} + +/** + * Convert a glyph from outlines to a bitmap that we can display. + */ +static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph) +{ + int render_mode; + + if (font->flags & BLF_MONOCHROME) { + render_mode = FT_RENDER_MODE_MONO; + } + else { + render_mode = FT_RENDER_MODE_NORMAL; } - if (err) { - BLI_spin_unlock(font->ft_lib_mutex); - return NULL; + /* Render the glyph curves to a bitmap. */ + FT_Error err = FT_Render_Glyph(glyph, render_mode); + if (err != 0) { + return false; } - /* get the glyph. */ - slot = font->face->glyph; - err = FT_Render_Glyph(slot, render_mode); + FT_Bitmap tempbitmap; if (font->flags & BLF_MONOCHROME) { /* Convert result from 1 bit per pixel to 8 bit per pixel */ - /* Accum errors for later, fine if not interested beyond "ok vs any error" */ + /* Accumulate errors for later, fine if not interested beyond "ok vs any error" */ FT_Bitmap_New(&tempbitmap); /* Does Blender use Pitch 1 always? It works so far */ - err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1); - err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap); + err += FT_Bitmap_Convert(font->ft_lib, &glyph->bitmap, &tempbitmap, 1); + err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &glyph->bitmap); err += FT_Bitmap_Done(font->ft_lib, &tempbitmap); } - if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) { - BLI_spin_unlock(font->ft_lib_mutex); - return NULL; + if (err || glyph->format != FT_GLYPH_FORMAT_BITMAP) { + return false; } - g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add"); - g->c = c; - g->idx = (FT_UInt)index; - bitmap = slot->bitmap; - g->dims[0] = (int)bitmap.width; - g->dims[1] = (int)bitmap.rows; + return true; +} - const int buffer_size = g->dims[0] * g->dims[1]; +/** \} */ - if (buffer_size != 0) { - if (font->flags & BLF_MONOCHROME) { - /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ - for (int i = 0; i < buffer_size; i++) { - bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0; - } +/* -------------------------------------------------------------------- */ +/** \name Glyph Transformations + * \{ */ + +/** + * Adjust the glyphs weight by a factor. + * + * \param factor: -1 (min stroke width) <= 0 (normal) => 1 (max boldness). + */ +static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + /* Fake bold if the font does not have this variable axis. */ + const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM, + glyph->face->size->metrics.x_scale); + FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f); + FT_Outline_EmboldenXY(&glyph->outline, change, change / 2); + if (monospaced) { + /* Widened fixed-pitch font needs a nudge left. */ + FT_Outline_Translate(&glyph->outline, change / -2, 0); + } + else { + /* Need to increase advance. */ + glyph->advance.x += change; + glyph->advance.y += change / 2; } + return true; + } + return false; +} - g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); - memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size); +/** + * Adjust the glyphs slant by a factor (making it oblique). + * + * \param factor: -1 (max negative) <= 0 (no slant) => 1 (max positive). + * + * \note that left-leaning italics are possible in some RTL writing systems. + */ +static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Matrix transform = {to_16dot16(1), to_16dot16(factor / 2.0f), 0, to_16dot16(1)}; + FT_Outline_Transform(&glyph->outline, &transform); + return true; } + return false; +} - g->advance = ((float)slot->advance.x) / 64.0f; - g->advance_i = (int)g->advance; - g->pos[0] = slot->bitmap_left; - g->pos[1] = slot->bitmap_top; - g->pitch = slot->bitmap.pitch; +/** + * Adjust the glyph width by factor. + * + * \param factor: -1 (min width) <= 0 (normal) => 1 (max width). + */ +static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + float scale = (factor * 0.4f) + 1.0f; /* 0.6f - 1.4f */ + FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)}; + FT_Outline_Transform(&glyph->outline, &matrix); + glyph->advance.x = (FT_Pos)((double)glyph->advance.x * scale); + return true; + } + return false; +} - FT_Outline_Get_CBox(&(slot->outline), &bbox); - g->box.xmin = ((float)bbox.xMin) / 64.0f; - g->box.xmax = ((float)bbox.xMax) / 64.0f; - g->box.ymin = ((float)bbox.yMin) / 64.0f; - g->box.ymax = ((float)bbox.yMax) / 64.0f; +/** + * Transform glyph to fit nicely within a fixed column width. + */ +static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + int gwidth = (int)(glyph->linearHoriAdvance >> 16); + if (gwidth > width) { + float scale = (float)width / (float)gwidth; + FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)}; + /* Narrowing all points also thins vertical strokes. */ + FT_Outline_Transform(&glyph->outline, &matrix); + const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f); + /* Horizontally widen strokes to counteract narrowing. */ + FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0); + } + else if (gwidth < width) { + /* Narrow glyphs only need to be centered. */ + int nudge = (width - gwidth) / 2; + FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0); + } + return true; + } + return false; +} - key = blf_hash(g->c); - BLI_addhead(&(gc->bucket[key]), g); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Access (Ensure/Free) + * \{ */ + +/** + * Create and return a fully-rendered bitmap glyph. + */ +static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, + FontBLF *glyph_font, + FT_UInt glyph_index) +{ + if (glyph_font != settings_font) { + FT_Set_Char_Size(glyph_font->face, + 0, + ((FT_F26Dot6)(settings_font->size)) * 64, + settings_font->dpi, + settings_font->dpi); + glyph_font->size = settings_font->size; + glyph_font->dpi = settings_font->dpi; + } + + FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index); + if (!glyph) { + return NULL; + } - BLI_spin_unlock(font->ft_lib_mutex); + if ((settings_font->flags & BLF_ITALIC) != 0) { + /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic + * version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when + * checking others. Worth reevaluating if we change default font. We could also + * narrow the glyph slightly as most italics do, but this one does not. */ + blf_glyph_transform_slant(glyph, 0.375f); + } + if ((settings_font->flags & BLF_BOLD) != 0) { + /* 70% of maximum weight results in the same amount of boldness and horizontal + * expansion as the bold version (`DejaVuSans-Bold.ttf`) of our default font. + * Worth reevaluating if we change default font. */ + blf_glyph_transform_weight(glyph, 0.7f, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); + } + + if (blf_glyph_render_bitmap(glyph_font, glyph)) { + return glyph; + } + return NULL; +} + +/** + * Create (or load from cache) a fully-rendered bitmap glyph. + */ +GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) +{ + GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode); + if (g) { + return g; + } + + /* Glyph might not come from the initial font. */ + FontBLF *font_with_glyph = font; + FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode); + + /* Glyphs are dynamically created as needed by font rendering. this means that + * to make font rendering thread safe we have to do locking here. note that this + * must be a lock for the whole library and not just per font, because the font + * renderer uses a shared buffer internally. */ + BLI_spin_lock(font_with_glyph->ft_lib_mutex); + + FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index); + + if (glyph) { + /* Save this glyph in the initial font's cache. */ + g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index); + } + + BLI_spin_unlock(font_with_glyph->ft_lib_mutex); return g; } @@ -337,6 +490,42 @@ void blf_glyph_free(GlyphBLF *g) MEM_freeN(g); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Bounds Calculation + * \{ */ + +static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) +{ + rect->xmin = floorf(x + (float)g->pos[0]); + rect->xmax = rect->xmin + (float)g->dims[0]; + rect->ymin = floorf(y + (float)g->pos[1]); + rect->ymax = rect->ymin - (float)g->dims[1]; +} + +static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) +{ + /* Intentionally check with `g->advance`, because this is the + * width used by BLF_width. This allows that the text slightly + * overlaps the clipping border to achieve better alignment. */ + rect->xmin = floorf(x); + rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]); + rect->ymin = floorf(y); + rect->ymax = rect->ymin - (float)g->dims[1]; +} + +static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font) +{ + blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Drawing + * \{ */ + static void blf_texture_draw(const unsigned char color[4], const int glyph_size[2], const int offset, @@ -395,31 +584,7 @@ static void blf_texture3_draw(const unsigned char color_in[4], blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2); } -static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) -{ - rect->xmin = floorf(x + (float)g->pos[0]); - rect->xmax = rect->xmin + (float)g->dims[0]; - rect->ymin = floorf(y + (float)g->pos[1]); - rect->ymax = rect->ymin - (float)g->dims[1]; -} - -static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) -{ - /* Intentionally check with g->advance, because this is the - * width used by BLF_width. This allows that the text slightly - * overlaps the clipping border to achieve better alignment. */ - rect->xmin = floorf(x); - rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]); - rect->ymin = floorf(y); - rect->ymax = rect->ymin - (float)g->dims[1]; -} - -static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font) -{ - blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y); -} - -void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y) +void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y) { if ((!g->dims[0]) || (!g->dims[1])) { return; @@ -526,3 +691,5 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); #endif } + +/** \} */ diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 6fd5e8b7503..cec20995dc6 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -52,7 +52,7 @@ struct FontBLF *blf_font_new(const char *name, const char *filename); struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); -void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); +void blf_font_size(struct FontBLF *font, float size, unsigned int dpi); void blf_font_draw(struct FontBLF *font, const char *str, size_t str_len, @@ -130,23 +130,17 @@ int blf_font_count_missing_chars(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, - unsigned int size, - unsigned int dpi); +struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi); struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font); struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font); void blf_glyph_cache_release(struct FontBLF *font); void blf_glyph_cache_clear(struct FontBLF *font); void blf_glyph_cache_free(struct GlyphCacheBLF *gc); -struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c); -struct GlyphBLF *blf_glyph_add(struct FontBLF *font, - struct GlyphCacheBLF *gc, - unsigned int index, - unsigned int c); +struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode); void blf_glyph_free(struct GlyphBLF *g); -void blf_glyph_render( +void blf_glyph_draw( struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y); #ifdef WIN32 diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index e90f82da7f3..46156edbb1f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -65,7 +65,7 @@ typedef struct GlyphCacheBLF { struct GlyphCacheBLF *prev; /* font size. */ - unsigned int size; + float size; /* and dpi. */ unsigned int dpi; @@ -86,13 +86,6 @@ typedef struct GlyphCacheBLF { int bitmap_len_landed; int bitmap_len_alloc; - /* and the bigger glyph in the font. */ - int glyph_width_max; - int glyph_height_max; - - /* ascender and descender value. */ - float ascender; - float descender; } GlyphCacheBLF; typedef struct GlyphBLF { @@ -212,7 +205,10 @@ typedef struct FontBLF { unsigned int dpi; /* font size. */ - unsigned int size; + float size; + + /* Column width when printing monospaced. */ + int fixed_width; /* max texture size. */ int tex_size_max; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 3153a55b697..bbdb26a61b6 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -95,7 +95,7 @@ void BLF_thumb_preview(const char *filename, const size_t draw_str_i18n_len = strlen(draw_str_i18n); int draw_str_i18n_nbr = 0; - blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi); + blf_font_size(font, (float)MAX2(font_size_min, font_size_curr), dpi); gc = blf_glyph_cache_find(font, font->size, font->dpi); /* There will be no matching glyph cache if blf_font_size() failed to set font size. */ if (!gc) { @@ -106,7 +106,7 @@ void BLF_thumb_preview(const char *filename, font_size_curr -= (font_size_curr / font_shrink); font_shrink += 1; - font->pos[1] -= gc->ascender * 1.1f; + font->pos[1] -= blf_font_ascender(font) * 1.1f; /* We fallback to default english strings in case not enough chars are available in current * font for given translated string (useful in non-latin i18n context, like Chinese, diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index db55daddba6..763e540fdd9 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -128,11 +128,12 @@ void action_groups_clear_tempflags(struct bAction *act); /** * Return whether the action has one unique point in time keyed. * - * This is mostly for the pose library, which will have different behaviour depending on whether an + * This is mostly for the pose library, which will have different behavior depending on whether an * Action corresponds to a "pose" (one keyframe) or "animation snippet" (multiple keyframes). * * \return `false` when there is no keyframe at all or keys on different points in time, `true` - * when exactly one point in time is keyed. */ + * when exactly one point in time is keyed. + */ bool BKE_action_has_single_frame(const struct bAction *act); /* Pose API ----------------- */ diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index bdb77571711..d071f782bd6 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -443,7 +443,9 @@ class AssetCatalog { * Simple, human-readable name for the asset catalog. This is stored on assets alongside the * catalog ID; the catalog ID is a UUID that is not human-readable, * so to avoid complete data-loss when the catalog definition file gets lost, - * we also store a human-readable simple name for the catalog. */ + * we also store a human-readable simple name for the catalog. + * + * It should fit in sizeof(AssetMetaData::catalog_simple_name) bytes. */ std::string simple_name; struct Flags { diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 7476474258b..2c83bef7517 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -43,12 +43,13 @@ struct ReportList; * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy). */ typedef enum AttributeDomain { - ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ - ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ - ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ - ATTR_DOMAIN_FACE = 2, /* Mesh Face */ - ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ - ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ + ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ + ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ + ATTR_DOMAIN_FACE = 2, /* Mesh Face */ + ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ + ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_INSTANCE = 5, /* Instance */ ATTR_DOMAIN_NUM } AttributeDomain; diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 6a87375e5e2..47f62b52a0f 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -115,10 +115,10 @@ struct AttributeInitDefault : public AttributeInit { * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - const blender::fn::GVArray *varray; + blender::fn::GVArray varray; - AttributeInitVArray(const blender::fn::GVArray *varray) - : AttributeInit(Type::VArray), varray(varray) + AttributeInitVArray(blender::fn::GVArray varray) + : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -150,9 +150,7 @@ namespace blender::bke { using fn::CPPType; using fn::GVArray; -using fn::GVArrayPtr; using fn::GVMutableArray; -using fn::GVMutableArrayPtr; const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); CustomDataType cpp_type_to_custom_data_type(const CPPType &type); @@ -164,14 +162,14 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) */ struct ReadAttributeLookup { /* The virtual array that is used to read from this attribute. */ - GVArrayPtr varray; + GVArray varray; /* Domain the attribute lives on in the geometry. */ AttributeDomain domain; /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -180,7 +178,7 @@ struct ReadAttributeLookup { */ struct WriteAttributeLookup { /* The virtual array that is used to read from and write to the attribute. */ - GVMutableArrayPtr varray; + GVMutableArray varray; /* Domain the attributes lives on in the geometry. */ AttributeDomain domain; /* Call this after changing the attribute to invalidate caches that depend on this attribute. */ @@ -189,7 +187,7 @@ struct WriteAttributeLookup { /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -209,7 +207,7 @@ class OutputAttribute { using SaveFn = std::function<void(OutputAttribute &)>; private: - GVMutableArrayPtr varray_; + GVMutableArray varray_; AttributeDomain domain_ = ATTR_DOMAIN_AUTO; SaveFn save_; std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_; @@ -219,7 +217,7 @@ class OutputAttribute { public: OutputAttribute(); OutputAttribute(OutputAttribute &&other); - OutputAttribute(GVMutableArrayPtr varray, + OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values); @@ -229,7 +227,7 @@ class OutputAttribute { operator bool() const; GVMutableArray &operator*(); - GVMutableArray *operator->(); + fn::GVMutableArray *operator->(); GVMutableArray &varray(); AttributeDomain domain() const; const CPPType &cpp_type() const; @@ -247,16 +245,14 @@ class OutputAttribute { template<typename T> class OutputAttribute_Typed { private: OutputAttribute attribute_; - std::unique_ptr<fn::GVMutableArray_Typed<T>> optional_varray_; - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: OutputAttribute_Typed(); OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute)) { if (attribute_) { - optional_varray_ = std::make_unique<fn::GVMutableArray_Typed<T>>(attribute_.varray()); - varray_ = &**optional_varray_; + varray_ = attribute_.varray().template typed<T>(); } } @@ -275,22 +271,22 @@ template<typename T> class OutputAttribute_Typed { operator bool() const { - return varray_ != nullptr; + return varray_; } VMutableArray<T> &operator*() { - return *varray_; + return varray_; } VMutableArray<T> *operator->() { - return varray_; + return &varray_; } VMutableArray<T> &varray() { - return *varray_; + return varray_; } AttributeDomain domain() const @@ -351,18 +347,17 @@ class CustomDataAttributes { std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const; - blender::fn::GVArrayPtr get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const; + blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const; template<typename T> - blender::fn::GVArray_Typed<T> get_for_read(const AttributeIDRef &attribute_id, - const T &default_value) const + blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - GVArrayPtr varray = this->get_for_read(attribute_id, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_for_read(attribute_id, type, &default_value); + return varray.typed<T>(); } std::optional<blender::fn::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id); @@ -465,7 +460,7 @@ inline bool AttributeIDRef::should_be_kept() const inline OutputAttribute::OutputAttribute() = default; inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default; -inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, +inline OutputAttribute::OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values) @@ -478,22 +473,22 @@ inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, inline OutputAttribute::operator bool() const { - return varray_.get() != nullptr; + return varray_; } inline GVMutableArray &OutputAttribute::operator*() { - return *varray_; + return varray_; } -inline GVMutableArray *OutputAttribute::operator->() +inline fn::GVMutableArray *OutputAttribute::operator->() { - return varray_.get(); + return &varray_; } inline GVMutableArray &OutputAttribute::varray() { - return *varray_; + return varray_; } inline AttributeDomain OutputAttribute::domain() const @@ -503,7 +498,7 @@ inline AttributeDomain OutputAttribute::domain() const inline const CPPType &OutputAttribute::cpp_type() const { - return varray_->type(); + return varray_.type(); } inline CustomDataType OutputAttribute::custom_data_type() const diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h index 1dd6d495276..4dd7145e66d 100644 --- a/source/blender/blenkernel/BKE_blender_copybuffer.h +++ b/source/blender/blenkernel/BKE_blender_copybuffer.h @@ -31,16 +31,18 @@ struct ReportList; struct bContext; /* copybuffer (wrapper for BKE_blendfile_write_partial) */ -void BKE_copybuffer_begin(struct Main *bmain_src); -void BKE_copybuffer_tag_ID(struct ID *id); -bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports); +void BKE_copybuffer_copy_begin(struct Main *bmain_src); +void BKE_copybuffer_copy_tag_ID(struct ID *id); +bool BKE_copybuffer_copy_end(struct Main *bmain_src, + const char *filename, + struct ReportList *reports); bool BKE_copybuffer_read(struct Main *bmain_dst, const char *libname, struct ReportList *reports, const uint64_t id_types_mask); int BKE_copybuffer_paste(struct bContext *C, const char *libname, - const short flag, + const int flag, struct ReportList *reports, const uint64_t id_types_mask); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 326ca746292..966d6c95421 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -31,15 +31,15 @@ extern "C" { */ /* Blender major and minor version. */ -#define BLENDER_VERSION 300 +#define BLENDER_VERSION 301 /* Blender patch version for bugfix releases. */ #define BLENDER_VERSION_PATCH 0 /** Blender release cycle stage: alpha/beta/rc/release. */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 42 +#define BLENDER_FILE_SUBVERSION 3 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h new file mode 100644 index 00000000000..9e4a498f5e7 --- /dev/null +++ b/source/blender/blenkernel/BKE_blendfile_link_append.h @@ -0,0 +1,112 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct BlendHandle; +struct ID; +struct Library; +struct LibraryLink_Params; +struct Main; +struct ReportList; +struct Scene; +struct ViewLayer; +struct View3D; + +typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext; +typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem; + +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new( + struct LibraryLink_Params *params); +void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context); +void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set); + +void BKE_blendfile_link_append_context_embedded_blendfile_set( + struct BlendfileLinkAppendContext *lapp_context, + const void *blendfile_mem, + int blendfile_memsize); +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + struct BlendfileLinkAppendContext *lapp_context); + +void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context, + const char *libname, + struct BlendHandle *blo_handle); +struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + struct BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata); +void BKE_blendfile_link_append_context_item_library_index_enable( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + const int library_index); +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context); + +void *BKE_blendfile_link_append_context_item_userdata_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +struct ID *BKE_blendfile_link_append_context_item_newid_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); + +typedef enum eBlendfileLinkAppendForeachItemFlag { + /** Loop over directly linked items (i.e. those explicitely defined by user code). */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0, + /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of + * direct ones). + * + * IMPORTANT: Those 'indirect' items currently may not cover **all** indrectly linked data. See + * comments in #foreach_libblock_link_append_callback. */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0, +} eBlendfileLinkAppendForeachItemFlag; +/** Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of + * each) of the items in given #BlendfileLinkAppendContext. + * + * \param userdata: An opaque void pointer passed to the `callback_function`. + * + * \return `true` if iteration should continue, `false` otherwise. */ +typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + void *userdata); +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata); + +void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); +void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); + +void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports, + struct Library *library, + const bool do_reload); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 452a08bc9c8..c5f1af4c755 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -78,7 +78,7 @@ void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool m /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset); -float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len); +float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, const float len); float BKE_brush_curve_strength(const struct Brush *br, float p, const float len); /* sampling */ diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 58a89d0207a..35e66908d54 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -119,10 +119,21 @@ class GeometryComponent { /* Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. * Returns null if the interpolation is not implemented. */ - virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const; + blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); + } + + template<typename T> + blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain) + .template typed<T>(); + } /* Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id); @@ -146,16 +157,15 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute on the given domain and data type. * Returns null when the attribute does not exist or cannot be converted to the requested domain * and data type. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type) const; /* Get a virtual array to read the data of an attribute on the given domain. The data type is * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the * requested domain. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain) const; /* Get a virtual array to read data of an attribute with the given data type. The domain is * left unchanged. Returns null when the attribute does not exist or cannot be converted to the @@ -165,25 +175,22 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute. If that is not possible, the returned * virtual array will contain a default value. This never returns null. */ - std::unique_ptr<blender::fn::GVArray> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value = nullptr) const; + blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value = nullptr) const; /* Should be used instead of the method above when the requested data type is known at compile * time for better type safety. */ template<typename T> - blender::fn::GVArray_Typed<T> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const T &default_value) const + blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - std::unique_ptr varray = this->attribute_get_for_read( - attribute_id, domain, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + return this->attribute_get_for_read(attribute_id, domain, type, &default_value) + .template typed<T>(); } /** @@ -234,6 +241,11 @@ class GeometryComponent { private: virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; + + virtual blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const; }; template<typename T> @@ -391,10 +403,6 @@ class MeshComponent : public GeometryComponent { Mesh *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -405,6 +413,11 @@ class MeshComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; /** A geometry component that stores a point cloud. */ @@ -469,10 +482,6 @@ class CurveComponent : public GeometryComponent { CurveEval *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -485,6 +494,11 @@ class CurveComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; class InstanceReference { @@ -637,6 +651,8 @@ class InstancesComponent : public GeometryComponent { mutable std::mutex almost_unique_ids_mutex_; mutable blender::Array<int> almost_unique_ids_; + blender::bke::CustomDataAttributes attributes_; + public: InstancesComponent(); ~InstancesComponent() = default; @@ -671,6 +687,9 @@ class InstancesComponent : public GeometryComponent { blender::Span<int> almost_unique_ids() const; + blender::bke::CustomDataAttributes &attributes(); + const blender::bke::CustomDataAttributes &attributes() const; + int attribute_domain_size(const AttributeDomain domain) const final; void foreach_referenced_geometry( @@ -759,9 +778,9 @@ class AttributeFieldInput : public fn::FieldInput { return name_; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -776,9 +795,9 @@ class IDAttributeFieldInput : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -815,9 +834,9 @@ class AnonymousAttributeFieldInput : public fn::FieldInput { return fn::Field<T>{field_input}; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index bacdd4adc76..d6cabbc1236 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -45,7 +45,6 @@ typedef struct Global { /** When set: `G_MAIN->name` contains valid relative base path. */ bool relbase_valid; - bool file_loaded; bool save_over; /** Strings of recent opened files. */ @@ -212,9 +211,9 @@ enum { G_TRANSFORM_FCURVES = (1 << 3), G_TRANSFORM_WM = (1 << 4), /** - * Set when transforming the cursor it's self. + * Set when transforming the cursor itself. * Used as a hint to draw the cursor (even when hidden). - * Otherwise it's not possible to see whats being transformed. + * Otherwise it's not possible to see what's being transformed. */ G_TRANSFORM_CURSOR = (1 << 5), }; diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index a9cd553a8fe..41b1bba10ba 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -128,8 +128,9 @@ struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit); + const bool select, + const bool flat_cap, + const int limit); void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 7a8c55071df..77f1d197844 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -47,9 +47,6 @@ struct anim; #define IMA_MAX_SPACE 64 #define IMA_UDIM_MAX 2000 -void BKE_images_init(void); -void BKE_images_exit(void); - void BKE_image_free_packedfiles(struct Image *image); void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index c8af1a91725..08b44959096 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -328,7 +328,7 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); { \ Object *_instance; \ Base *_base; \ - for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \ + for (_base = (Base *)(view_layer)->object_bases.first; _base; _base = _base->next) { \ _instance = _base->object; #define FOREACH_OBJECT_END \ diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 68399959a37..359fb72534a 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -137,8 +137,10 @@ enum { LIB_ID_COPY_SHAPEKEY = 1 << 26, /** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */ LIB_ID_COPY_NODETREE_LOCALIZE = 1 << 27, - /** EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we - duplicate scene/collections, or objects. */ + /** + * EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we + * duplicate scene/collections, or objects. + */ LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28, /* *** Helper 'defines' gathering most common flag sets. *** */ diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index 957a623577e..30c742e3af6 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -143,7 +143,8 @@ enum { typedef struct LibraryForeachIDData LibraryForeachIDData; -bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data, +bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data); +void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data, struct ID **id_pp, int cb_flag); int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data); @@ -154,7 +155,8 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach #define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \ { \ CHECK_TYPE_ANY((_id), ID *, void *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return; \ } \ } \ @@ -163,13 +165,23 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach #define BKE_LIB_FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \ { \ CHECK_TYPE(&((_id_super)->id), ID *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return; \ } \ } \ ((void)0) -bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp); +#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(_data, _func_call) \ + { \ + _func_call; \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ + return; \ + } \ + } \ + ((void)0) + +void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp); void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data); /* Loop over all of the ID's this datablock links to. */ diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index c70521f9593..5e154459a6c 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -89,6 +89,12 @@ enum { * dealing with IDs temporarily out of Main, but which will be put in it ultimately). */ ID_REMAP_FORCE_USER_REFCOUNT = 1 << 8, + /** + * Force obdata pointers to also be processed, even when object (`id_owner`) is in Edit mode. + * This is required by some tools creating/deleting IDs while operating in Edit mode, like e.g. + * the 'separate' mesh operator. + */ + ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9, }; /* NOTE: Requiring new_id to be non-null, this *may* not be the case ultimately, @@ -111,8 +117,8 @@ void BKE_libblock_relink_ex(struct Main *bmain, void *new_idv, const short remap_flags) ATTR_NONNULL(1, 2); -void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL(); -void BKE_libblock_relink_to_newid_new(struct Main *bmain, struct ID *id) ATTR_NONNULL(); +void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, const int remap_flag) + ATTR_NONNULL(); typedef void (*BKE_library_free_notifier_reference_cb)(const void *); typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 58fea6d462c..5ed1b512fd5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -121,12 +121,11 @@ class MFDataType; } // namespace fn } // namespace blender +using CPPTypeHandle = blender::fn::CPPType; using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder); -using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); -using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); @@ -138,6 +137,7 @@ typedef void *SocketGetCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPValueFunction; typedef void *SocketGetCPPValueFunction; +typedef struct CPPTypeHandle CPPTypeHandle; #endif /** @@ -197,11 +197,11 @@ typedef struct bNodeSocketType { void (*free_self)(struct bNodeSocketType *stype); /* Return the CPPType of this socket. */ - SocketGetCPPTypeFunction get_base_cpp_type; + const CPPTypeHandle *base_cpp_type; /* Get the value of this socket in a generic way. */ SocketGetCPPValueFunction get_base_cpp_value; /* Get geometry nodes cpp type. */ - SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type; + const CPPTypeHandle *geometry_nodes_cpp_type; /* Get geometry nodes cpp value. */ SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value; } bNodeSocketType; @@ -318,8 +318,6 @@ typedef struct bNodeType { /* optional handling of link insertion */ void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); - /* Update the internal links list, for muting and disconnect operators. */ - void (*update_internal_links)(struct bNodeTree *, struct bNode *node); void (*free_self)(struct bNodeType *ntype); @@ -344,6 +342,9 @@ typedef struct bNodeType { /* Declaration to be used when it is not dynamic. */ NodeDeclarationHandle *fixed_declaration; + /** True when the node cannot be muted. */ + bool no_muting; + /* RNA integration */ ExtensionRNA rna_ext; } bNodeType; @@ -731,11 +732,15 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node); int nodeSocketIsHidden(const struct bNodeSocket *sock); void ntreeTagUsedSockets(struct bNodeTree *ntree); -void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available); +void nodeSetSocketAvailability(struct bNodeTree *ntree, + struct bNodeSocket *sock, + bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); -void nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node); +bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node); +bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node); +void nodeSocketDeclarationsUpdate(struct bNode *node); /* Node Clipboard */ void BKE_node_clipboard_init(const struct bNodeTree *ntree); @@ -887,8 +892,6 @@ void node_type_exec(struct bNodeType *ntype, NodeFreeExecFunction free_exec_fn, NodeExecFunction exec_fn); void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); -void node_type_internal_links(struct bNodeType *ntype, - void (*update_internal_links)(struct bNodeTree *, struct bNode *)); /** \} */ diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 55a4f6ffcfd..67eaa7c12c9 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -187,14 +187,14 @@ class Spline { blender::MutableSpan<T> dst) const { this->sample_with_index_factors( - blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst)); + blender::fn::GVArray(src), index_factors, blender::fn::GMutableSpan(dst)); } template<typename T> void sample_with_index_factors(blender::Span<T> src, blender::Span<float> index_factors, blender::MutableSpan<T> dst) const { - this->sample_with_index_factors(blender::VArray_For_Span(src), index_factors, dst); + this->sample_with_index_factors(blender::VArray<T>::ForSpan(src), index_factors, dst); } /** @@ -202,13 +202,11 @@ class Spline { * evaluated points. For poly splines, the lifetime of the returned virtual array must not * exceed the lifetime of the input data. */ - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( - const blender::fn::GVArray &src) const = 0; - blender::fn::GVArrayPtr interpolate_to_evaluated(blender::fn::GSpan data) const; - template<typename T> - blender::fn::GVArray_Typed<T> interpolate_to_evaluated(blender::Span<T> data) const + virtual blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const = 0; + blender::fn::GVArray interpolate_to_evaluated(blender::fn::GSpan data) const; + template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const { - return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data))); + return this->interpolate_to_evaluated(blender::fn::GSpan(data)).typed<T>(); } protected: @@ -307,20 +305,20 @@ class BezierSpline final : public Spline { blender::MutableSpan<HandleType> handle_types_left(); blender::Span<blender::float3> handle_positions_left() const; /** - * Get writable access to the hande position. + * Get writable access to the handle position. * * \param write_only: pass true for an uninitialized spline, this prevents accessing - * uninitialized memory while autogenerating handles. + * uninitialized memory while auto-generating handles. */ blender::MutableSpan<blender::float3> handle_positions_left(bool write_only = false); blender::Span<HandleType> handle_types_right() const; blender::MutableSpan<HandleType> handle_types_right(); blender::Span<blender::float3> handle_positions_right() const; /** - * Get writable access to the hande position. + * Get writable access to the handle position. * * \param write_only: pass true for an uninitialized spline, this prevents accessing - * uninitialized memory while autogenerating handles. + * uninitialized memory while auto-generating handles. */ blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false); void ensure_auto_handles() const; @@ -350,7 +348,7 @@ class BezierSpline final : public Spline { }; InterpolationData interpolation_data_from_index_factor(const float index_factor) const; - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( + virtual blender::fn::GVArray interpolate_to_evaluated( const blender::fn::GVArray &src) const override; void evaluate_segment(const int index, @@ -487,7 +485,7 @@ class NURBSpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -538,7 +536,7 @@ class PolySpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -582,6 +580,9 @@ struct CurveEval { blender::Array<int> evaluated_point_offsets() const; blender::Array<float> accumulated_spline_lengths() const; + float total_length() const; + int total_control_point_size() const; + void mark_cache_invalid(); void assert_valid_point_attributes() const; diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index 9532da8c23c..dd8ae7ea554 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once + #include "BLI_span.hh" #include "DNA_modifier_types.h" diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d4ec7fd703d..a08f1b81dbe 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -100,6 +100,7 @@ set(SRC intern/blender_undo.c intern/blender_user_menu.c intern/blendfile.c + intern/blendfile_link_append.c intern/boids.c intern/bpath.c intern/brush.c @@ -192,7 +193,7 @@ set(SRC intern/material.c intern/mball.c intern/mball_tessellate.c - intern/mesh.c + intern/mesh.cc intern/mesh_boolean_convert.cc intern/mesh_convert.cc intern/mesh_evaluate.cc @@ -326,6 +327,7 @@ set(SRC BKE_blender_user_menu.h BKE_blender_version.h BKE_blendfile.h + BKE_blendfile_link_append.h BKE_boids.h BKE_bpath.h BKE_brush.h diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 842902b51ed..2cc1cba99cd 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -176,7 +176,7 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data) bAction *act = (bAction *)id; LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 23d2c4fe55f..21887d514d9 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -294,7 +294,7 @@ bool BKE_animdata_id_is_animated(const struct ID *id) void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data) { LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER); diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 08a3b7d0bbb..d872dc67dcb 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -279,23 +279,31 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len) /** * Gets a good default directory for fonts. */ -bool BKE_appdir_font_folder_default( - /* This parameter can only be `const` on non-windows platforms. - * NOLINTNEXTLINE: readability-non-const-parameter. */ - char *dir) +bool BKE_appdir_font_folder_default(char *dir) { - bool success = false; + char test_dir[FILE_MAXDIR]; + test_dir[0] = '\0'; + #ifdef WIN32 wchar_t wpath[FILE_MAXDIR]; - success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0); - if (success) { + if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) { wcscat(wpath, L"\\"); - BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR); + BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir)); + } +#elif defined(__APPLE__) + const char *home = BLI_getenv("HOME"); + if (home) { + BLI_path_join(test_dir, sizeof(test_dir), home, "Library", "Fonts", NULL); } +#else + STRNCPY(test_dir, "/usr/share/fonts"); #endif - /* TODO: Values for other platforms. */ - UNUSED_VARS(dir); - return success; + + if (test_dir[0] && BLI_exists(test_dir)) { + BLI_strncpy(dir, test_dir, FILE_MAXDIR); + return true; + } + return false; } /** \} */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b64b050f4e7..b830c9de5f5 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -161,30 +161,36 @@ static void armature_free_data(struct ID *id) static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data) { - IDP_foreach_property( - bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - armature_foreach_id_bone(curbone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data)); } } static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDData *data) { - IDP_foreach_property( - edit_bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(edit_bone->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } static void armature_foreach_id(ID *id, LibraryForeachIDData *data) { bArmature *arm = (bArmature *)id; LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - armature_foreach_id_bone(bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(bone, data)); } if (arm->edbo != NULL) { LISTBASE_FOREACH (EditBone *, edit_bone, arm->edbo) { - armature_foreach_id_editbone(edit_bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_editbone(edit_bone, data)); } } } diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 7bea089b9bf..59e402b6680 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -21,14 +21,12 @@ #include <cstring> #include "DNA_ID.h" -#include "DNA_asset_types.h" #include "DNA_defaults.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_ref.hh" #include "BLI_string_utils.h" -#include "BLI_utildefines.h" #include "BLI_uuid.h" #include "BKE_asset.h" diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 33405c9aeae..9ef66d23aea 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -18,25 +18,20 @@ * \ingroup bke */ +#include <fstream> +#include <set> + #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" -#include "BKE_preferences.h" #include "BLI_fileops.h" #include "BLI_path_util.h" -#include "BLI_set.hh" -#include "BLI_string_ref.hh" - -#include "DNA_userdef_types.h" /* For S_ISREG() and S_ISDIR() on Windows. */ #ifdef WIN32 # include "BLI_winstuff.h" #endif -#include <fstream> -#include <set> - namespace blender::bke { const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt"; diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index 2cef34966f8..ba8f8716823 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -24,6 +24,7 @@ #include "BLI_fileops.h" #include "BLI_path_util.h" +#include "DNA_asset_types.h" #include "DNA_userdef_types.h" #include "testing/testing.h" @@ -930,6 +931,28 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name) << "Changing the path should update the simplename of children."; } +TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename) +{ + AssetCatalogService service(asset_library_root_); + service.load_from_disk(asset_library_root_ + "/" + + AssetCatalogService::DEFAULT_CATALOG_FILENAME); + const std::string new_path = + "this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets"; + ASSERT_GT(new_path.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "This test case should work with paths longer than AssetMetaData::catalog_simple_name"; + + service.update_catalog_path(UUID_POSES_RUZENA, new_path); + + const std::string new_simple_name = service.find_catalog(UUID_POSES_RUZENA)->simple_name; + EXPECT_LT(new_simple_name.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "The new simple name should fit in the asset metadata."; + EXPECT_EQ("...very-long-path-that-exceeds-the-simple-name-length-of-assets", new_simple_name) + << "Changing the path should update the simplename."; + EXPECT_EQ("...long-path-that-exceeds-the-simple-name-length-of-assets-face", + service.find_catalog(UUID_POSES_RUZENA_FACE)->simple_name) + << "Changing the path should update the simplename of children."; +} + TEST_F(AssetCatalogTest, update_catalog_path_add_slashes) { AssetCatalogService service(asset_library_root_); diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index aae8a289d32..68e43852a21 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -18,9 +18,9 @@ * \ingroup bke */ -#include "BKE_asset_catalog.hh" +#include <memory> + #include "BKE_asset_library.hh" -#include "BKE_callbacks.h" #include "BKE_main.h" #include "BKE_preferences.h" @@ -29,12 +29,8 @@ #include "DNA_asset_types.h" #include "DNA_userdef_types.h" -#include "MEM_guardedalloc.h" - #include "asset_library_service.hh" -#include <memory> - bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true; /** diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index 7cf95ee4cc1..d202d6462cf 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -20,16 +20,12 @@ #include "asset_library_service.hh" -#include "BKE_asset_library.hh" #include "BKE_blender.h" -#include "BKE_callbacks.h" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BLI_string_ref.hh" -#include "MEM_guardedalloc.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"bke.asset_service"}; diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index e26ae05301e..ee910cab945 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -19,7 +19,7 @@ #include "asset_library_service.hh" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BKE_appdir.h" diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index cd394a4ca42..3f2c1f13337 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -50,9 +50,7 @@ using blender::bke::AttributeIDRef; using blender::bke::OutputAttribute; using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_SingleValue; -using blender::fn::GVMutableArray_For_GMutableSpan; +using blender::fn::GVMutableArrayImpl_For_GMutableSpan; namespace blender::bke { @@ -166,16 +164,18 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ static int attribute_domain_priority(const AttributeDomain domain) { switch (domain) { - case ATTR_DOMAIN_CURVE: + case ATTR_DOMAIN_INSTANCE: return 0; - case ATTR_DOMAIN_FACE: + case ATTR_DOMAIN_CURVE: return 1; - case ATTR_DOMAIN_EDGE: + case ATTR_DOMAIN_FACE: return 2; - case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_EDGE: return 3; - case ATTR_DOMAIN_CORNER: + case ATTR_DOMAIN_POINT: return 4; + case ATTR_DOMAIN_CORNER: + return 5; default: /* Domain not supported in nodes yet. */ BLI_assert_unreachable(); @@ -207,7 +207,7 @@ fn::GMutableSpan OutputAttribute::as_span() { if (!optional_span_varray_) { const bool materialize_old_values = !ignore_old_values_; - optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(*varray_, + optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_, materialize_old_values); } fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_; @@ -257,8 +257,8 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -313,8 +313,8 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -345,8 +345,7 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, return layer.name == attribute_id.name(); } -GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( - const GeometryComponent &component) const +GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); if (custom_data == nullptr) { @@ -511,7 +510,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( continue; } GSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVArray_For_GSpan>(data), domain_}; + return {GVArray::ForSpan(data), domain_}; } return {}; } @@ -541,7 +540,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( continue; } GMutableSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVMutableArray_For_GMutableSpan>(data), domain_}; + return {GVMutableArray::ForSpan(data), domain_}; } return {}; } @@ -751,25 +750,25 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at * value if the attribute doesn't exist. If no default value is provided, the default value for the * type will be used. */ -GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const +GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const { const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); std::optional<GSpan> attribute = this->get_for_read(attribute_id); if (!attribute) { const int domain_size = this->size_; - return std::make_unique<GVArray_For_SingleValue>( + return GVArray::ForSingle( *type, domain_size, (default_value == nullptr) ? type->default_value() : default_value); } if (attribute->type() == *type) { - return std::make_unique<GVArray_For_GSpan>(*attribute); + return GVArray::ForSpan(*attribute); } const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type); + return conversions.try_convert(GVArray::ForSpan(*attribute), *type); } std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id) @@ -922,8 +921,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {}; } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, +blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { @@ -1110,15 +1109,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data( return result; } -static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type( - std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type) +static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray, + const blender::fn::CPPType &to_type) { const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); return conversions.try_convert(std::move(varray), to_type); } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type) const @@ -1128,7 +1127,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return {}; } - std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray); + blender::fn::GVArray varray = std::move(attribute.varray); if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) { varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); if (!varray) { @@ -1138,7 +1137,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - if (varray->type() != *cpp_type) { + if (varray.type() != *cpp_type) { varray = try_adapt_data_type(std::move(varray), *cpp_type); if (!varray) { return {}; @@ -1148,7 +1147,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return varray; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain) const { if (!this->attribute_domain_supported(domain)) { @@ -1176,7 +1175,7 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( } const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(type != nullptr); - if (attribute.varray->type() == *type) { + if (attribute.varray.type() == *type) { return attribute; } const blender::nodes::DataTypeConversions &conversions = @@ -1184,14 +1183,12 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain}; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read( - const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const +blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value) const { - std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read( - attribute_id, domain, data_type); + blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); if (varray) { return varray; } @@ -1200,11 +1197,11 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read default_value = type->default_value(); } const int domain_size = this->attribute_domain_size(domain); - return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value); + return blender::fn::GVArray::ForSingle(*type, domain_size, default_value); } class GVMutableAttribute_For_OutputAttribute - : public blender::fn::GVMutableArray_For_GMutableSpan { + : public blender::fn::GVMutableArrayImpl_For_GMutableSpan { public: GeometryComponent *component; std::string attribute_name; @@ -1213,7 +1210,7 @@ class GVMutableAttribute_For_OutputAttribute GVMutableAttribute_For_OutputAttribute(GMutableSpan data, GeometryComponent &component, const AttributeIDRef &attribute_id) - : blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component) + : blender::fn::GVMutableArrayImpl_For_GMutableSpan(data), component(&component) { if (attribute_id.is_named()) { this->attribute_name = attribute_id.name(); @@ -1239,7 +1236,8 @@ static void save_output_attribute(OutputAttribute &output_attribute) using namespace blender::bke; GVMutableAttribute_For_OutputAttribute &varray = - dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray()); + dynamic_cast<GVMutableAttribute_For_OutputAttribute &>( + *output_attribute.varray().get_implementation()); GeometryComponent &component = *varray.component; AttributeIDRef attribute_id; @@ -1267,7 +1265,7 @@ static void save_output_attribute(OutputAttribute &output_attribute) BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer); for (const int i : IndexRange(varray.size())) { varray.get(i, buffer); - write_attribute.varray->set_by_relocate(i, buffer); + write_attribute.varray.set_by_relocate(i, buffer); } if (write_attribute.tag_modified_fn) { write_attribute.tag_modified_fn(); @@ -1310,9 +1308,9 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, if (!attribute) { if (default_value) { const int64_t domain_size = component.attribute_domain_size(domain); - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; - component.attribute_try_create_builtin(attribute_name, - AttributeInitVArray(&default_varray)); + component.attribute_try_create_builtin( + attribute_name, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); @@ -1327,9 +1325,8 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, /* Builtin attribute is on different domain. */ return {}; } - - GVMutableArrayPtr varray = std::move(attribute.varray); - if (varray->type() == *cpp_type) { + GVMutableArray varray = std::move(attribute.varray); + if (varray.type() == *cpp_type) { /* Builtin attribute matches exactly. */ return OutputAttribute(std::move(varray), domain, @@ -1349,9 +1346,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id); if (!attribute) { if (default_value) { - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; component.attribute_try_create( - attribute_id, domain, data_type, AttributeInitVArray(&default_varray)); + attribute_id, + domain, + data_type, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault()); @@ -1363,7 +1362,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, return {}; } } - if (attribute.domain == domain && attribute.varray->type() == *cpp_type) { + if (attribute.domain == domain && attribute.varray.type() == *cpp_type) { /* Existing generic attribute matches exactly. */ return OutputAttribute(std::move(attribute.varray), @@ -1382,11 +1381,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, } else { /* Fill the temporary array with values from the existing attribute. */ - GVArrayPtr old_varray = component.attribute_get_for_read( + GVArray old_varray = component.attribute_get_for_read( attribute_id, domain, data_type, default_value); - old_varray->materialize_to_uninitialized(IndexRange(domain_size), data); + old_varray.materialize_to_uninitialized(IndexRange(domain_size), data); } - GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>( + GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>( GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id); return OutputAttribute(std::move(varray), domain, save_output_attribute, true); @@ -1410,21 +1409,21 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only( namespace blender::bke { -const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const +GVArray AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type); + GVArray attribute = component.attribute_try_get_for_read(name_, domain, data_type); if (attribute) { - return scope.add(std::move(attribute)); + return attribute; } } - return nullptr; + return {}; } std::string AttributeFieldInput::socket_inspection_name() const @@ -1451,31 +1450,32 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_INSTANCE: return "id"; default: return ""; } } -const GVArray *IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const +GVArray IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const StringRef name = get_random_id_attribute_name(domain); - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); + GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); if (attribute) { - BLI_assert(attribute->size() == component.attribute_domain_size(domain)); - return scope.add(std::move(attribute)); + BLI_assert(attribute.size() == component.attribute_domain_size(domain)); + return attribute; } /* Use the index as the fallback if no random ID attribute exists. */ return fn::IndexFieldInput::get_index_varray(mask, scope); } - return nullptr; + return {}; } std::string IDAttributeFieldInput::socket_inspection_name() const @@ -1495,19 +1495,20 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; } -const GVArray *AnonymousAttributeFieldInput::get_varray_for_context( - const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const +GVArray AnonymousAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read( + GVArray attribute = component.attribute_try_get_for_read( anonymous_id_.get(), domain, data_type); - return scope.add(std::move(attribute)); + return attribute; } - return nullptr; + return {}; } std::string AnonymousAttributeFieldInput::socket_inspection_name() const diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 140498bdb01..b77d7010efa 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -24,9 +24,6 @@ namespace blender::bke { -using fn::GVArrayPtr; -using fn::GVMutableArrayPtr; - /** * Utility to group together multiple functions that are used to access custom data on geometry * components in a generic way. @@ -86,7 +83,7 @@ class BuiltinAttributeProvider { { } - virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0; virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0; virtual bool try_delete(GeometryComponent &component) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component), @@ -188,8 +185,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { */ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { private: - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); const AttributeDomain domain_; const CustomDataType attribute_type_; const CustomDataType stored_type_; @@ -232,8 +229,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { * if the stored type is the same as the attribute type. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; @@ -266,7 +263,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final; + GVArray try_get_for_read(const GeometryComponent &component) const final; WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final; bool try_delete(GeometryComponent &component) const final; bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 97f8bddc043..fb65a9bec7e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -90,7 +90,6 @@ void BKE_blender_free(void) IMB_exit(); BKE_cachefiles_exit(); - BKE_images_exit(); DEG_free_node_types(); BKE_brush_system_exit(); diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 9c9f898afef..f8b943d3479 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -57,20 +57,26 @@ /** \name Copy/Paste `.blend`, partial saves. * \{ */ -void BKE_copybuffer_begin(Main *bmain_src) +/** Initialize a copy operation. */ +void BKE_copybuffer_copy_begin(Main *bmain_src) { BKE_blendfile_write_partial_begin(bmain_src); } -void BKE_copybuffer_tag_ID(ID *id) +/** Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin. */ +void BKE_copybuffer_copy_tag_ID(ID *id) { BKE_blendfile_write_partial_tag_ID(id, true); } /** - * \return Success. + * Finalize a copy operation into given .blend file 'buffer'. + * + * \param filename: Full path to the .blend file used as copy/paste buffer. + * + * \return true on success, false otherwise. */ -bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports) +bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports) { const int write_flags = 0; const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; @@ -82,6 +88,16 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo return retval; } +/** + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return true on success, false otherwise. + */ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports, @@ -116,12 +132,22 @@ bool BKE_copybuffer_read(Main *bmain_dst, } /** - * \return Number of IDs directly pasted from the buffer - * (does not includes indirectly pulled out ones). + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control + * link/append behavior. + * \note: Ignores #FILE_LINK flag, since it always appends IDs. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return Number of IDs directly pasted from the buffer (does not includes indirectly linked + * ones). */ int BKE_copybuffer_paste(bContext *C, const char *libname, - const short flag, + const int flag, ReportList *reports, const uint64_t id_types_mask) { diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c new file mode 100644 index 00000000000..36f03990953 --- /dev/null +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -0,0 +1,1566 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + * + * High level `.blend` file link/append code, + * including linking/appending several IDs from different libraries, handling instanciations of + * collections/objects/obdata in current scene. + */ + +#include <stdlib.h> +#include <string.h> + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_key_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BLI_bitmap.h" +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_idtype.h" +#include "BKE_key.h" +#include "BKE_layer.h" +#include "BKE_lib_id.h" +#include "BKE_lib_override.h" +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_rigidbody.h" +#include "BKE_scene.h" + +#include "BKE_blendfile_link_append.h" + +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +static CLG_LogRef LOG = {"bke.blendfile_link_append"}; + +/* -------------------------------------------------------------------- */ +/** \name Link/append context implementation and public management API. + * \{ */ + +typedef struct BlendfileLinkAppendContextItem { + /** Name of the ID (without the heading two-chars IDcode). */ + char *name; + /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */ + BLI_bitmap *libraries; + /** ID type. */ + short idcode; + + /** Type of action to perform on this item, and general status tag information. + * NOTE: Mostly used by append post-linking processing. */ + char action; + char tag; + + /** Newly linked ID (NULL until it has been successfully linked). */ + ID *new_id; + /** Library ID from which the #new_id has been linked (NULL until it has been successfully + * linked). */ + Library *source_library; + /** Opaque user data pointer. */ + void *userdata; +} BlendfileLinkAppendContextItem; + +/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */ +typedef struct BlendfileLinkAppendContextLibrary { + char *path; /* Absolute .blend file path. */ + BlendHandle *blo_handle; /* Blend file handle, if any. */ + bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */ + /* The blendfile report associated with the `blo_handle`, if owned. */ + BlendFileReadReport bf_reports; +} BlendfileLinkAppendContextLibrary; + +typedef struct BlendfileLinkAppendContext { + /** List of library paths to search IDs in. */ + LinkNodePair libraries; + /** List of all ID to try to link from #libraries. */ + LinkNodePair items; + int num_libraries; + int num_items; + /** Linking/appending parameters. Including bmain, scene, viewlayer and view3d. */ + LibraryLink_Params *params; + + /** Allows to easily find an existing items from an ID pointer. */ + GHash *new_id_to_item; + + /** Runtime info used by append code to manage re-use of already appended matching IDs. */ + GHash *library_weak_reference_mapping; + + /** Embedded blendfile and its size, if needed. */ + const void *blendfile_mem; + size_t blendfile_memsize; + + /** Internal 'private' data */ + MemArena *memarena; +} BlendfileLinkAppendContext; + +typedef struct BlendfileLinkAppendContextCallBack { + BlendfileLinkAppendContext *lapp_context; + BlendfileLinkAppendContextItem *item; + ReportList *reports; + +} BlendfileLinkAppendContextCallBack; + +/* Actions to apply to an item (i.e. linked ID). */ +enum { + LINK_APPEND_ACT_UNSET = 0, + LINK_APPEND_ACT_KEEP_LINKED, + LINK_APPEND_ACT_REUSE_LOCAL, + LINK_APPEND_ACT_MAKE_LOCAL, + LINK_APPEND_ACT_COPY_LOCAL, +}; + +/* Various status info about an item (i.e. linked ID). */ +enum { + /* An indirectly linked ID. */ + LINK_APPEND_TAG_INDIRECT = 1 << 0, +}; + +static BlendHandle *link_append_context_library_blohandle_ensure( + BlendfileLinkAppendContext *lapp_context, + BlendfileLinkAppendContextLibrary *lib_context, + ReportList *reports) +{ + if (reports != NULL) { + lib_context->bf_reports.reports = reports; + } + + char *libname = lib_context->path; + BlendHandle *blo_handle = lib_context->blo_handle; + if (blo_handle == NULL) { + if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { + blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem, + (int)lapp_context->blendfile_memsize, + &lib_context->bf_reports); + } + else { + blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports); + } + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = true; + } + + return blo_handle; +} + +static void link_append_context_library_blohandle_release( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextLibrary *lib_context) +{ + if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) { + BLO_blendhandle_close(lib_context->blo_handle); + lib_context->blo_handle = NULL; + } +} + +/** Allocate and initialize a new context to link/append datablocks. + * + * \param flag a combination of #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags + * from BLO_readfile.h + */ +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params) +{ + MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context)); + + lapp_context->params = params; + lapp_context->memarena = ma; + + return lapp_context; +} + +/** Free a link/append context. */ +void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context) +{ + if (lapp_context->new_id_to_item != NULL) { + BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL); + } + + for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL; + liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + BLI_assert(lapp_context->library_weak_reference_mapping == NULL); + + BLI_memarena_free(lapp_context->memarena); +} + +/** Set or clear flags in given \a lapp_context. + * + * \param do_set Set the given \a flag if true, clear it otherwise. + */ +void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set) +{ + if (do_set) { + lapp_context->params->flag |= flag; + } + else { + lapp_context->params->flag &= ~flag; + } +} + +/** Store reference to a Blender's embedded memfile into the context. + * + * \note This is required since embedded startup blender file is handled in `ED` module, which + * cannot be linked in BKE code. + */ +void BKE_blendfile_link_append_context_embedded_blendfile_set( + BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize) +{ + BLI_assert_msg(lapp_context->blendfile_mem == NULL, + "Please explicitely clear reference to an embedded blender memfile before " + "setting a new one"); + lapp_context->blendfile_mem = blendfile_mem; + lapp_context->blendfile_memsize = (size_t)blendfile_memsize; +} + +/** Clear reference to Blender's embedded startup file into the context. */ +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->blendfile_mem = NULL; + lapp_context->blendfile_memsize = 0; +} + +/** Add a new source library to search for items to be linked to the given link/append context. + * + * \param libname: the absolute path to the library blend file. + * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this + * is only borrowed for linking purpose, no releasing or other management will + * be performed by #BKE_blendfile_link_append code on it. + * + * \note *Never* call BKE_blendfile_link_append_context_library_add() after having added some + * items. */ +void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context, + const char *libname, + BlendHandle *blo_handle) +{ + BLI_assert(lapp_context->items.list == NULL); + + BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*lib_context)); + + size_t len = strlen(libname) + 1; + char *libpath = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(libpath, libname, len); + + lib_context->path = libpath; + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = (blo_handle == NULL); + + BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena); + lapp_context->num_libraries++; +} + +/** Add a new item (datablock name and idcode) to be searched and linked/appended from libraries + * associated to the given context. + * + * \param userdata: an opaque user-data pointer stored in generated link/append item. */ +BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata) +{ + BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*item)); + size_t len = strlen(idname) + 1; + + item->name = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(item->name, idname, len); + item->idcode = idcode; + item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries); + + item->new_id = NULL; + item->action = LINK_APPEND_ACT_UNSET; + item->userdata = userdata; + + BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena); + lapp_context->num_items++; + + return item; +} + +/** Enable search of the given \a item into the library stored at given index in the link/append + * context. */ +void BKE_blendfile_link_append_context_item_library_index_enable( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextItem *item, + const int library_index) +{ + BLI_BITMAP_ENABLE(item->libraries, library_index); +} + +/** Check if given link/append context is empty (has no items to process) or not. */ +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context) +{ + return lapp_context->num_items == 0; +} + +void *BKE_blendfile_link_append_context_item_userdata_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->userdata; +} + +ID *BKE_blendfile_link_append_context_item_newid_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->new_id; +} + +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *UNUSED(lapp_context), + struct BlendfileLinkAppendContextItem *item) +{ + return item->idcode; +} + +/** Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext, and + * call the `callback_function` on them. + * + * \param flag: Control which type of items to process (see + * #eBlendfileLinkAppendForeachItemFlag enum flags). + * \param userdata: An opaque void pointer passed to the `callback_function`. + */ +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata) +{ + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + continue; + } + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) { + continue; + } + + if (!callback_function(lapp_context, item, userdata)) { + break; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library link/append helper functions. + * + * \{ */ + +/* Struct gathering all required data to handle instantiation of loose data-blocks. */ +typedef struct LooseDataInstantiateContext { + BlendfileLinkAppendContext *lapp_context; + + /* The collection in which to add loose collections/objects. */ + Collection *active_collection; +} LooseDataInstantiateContext; + +static bool object_in_any_scene(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (BKE_scene_object_find(sce, ob)) { + return true; + } + } + + return false; +} + +static bool object_in_any_collection(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, ob)) { + return true; + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->master_collection != NULL && + BKE_collection_has_object(scene->master_collection, ob)) { + return true; + } + } + + return false; +} + +static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context, + BlendfileLinkAppendContextItem *item) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + /* In linking case, we always want to handle instantiation. */ + if (lapp_context->params->flag & FILE_LINK) { + return item->new_id; + } + + /* We consider that if we either kept it linked, or re-used already local data, instantiation + * status of those should not be modified. */ + if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) { + return NULL; + } + + ID *id = item->new_id; + if (id == NULL) { + return NULL; + } + + if (item->action == LINK_APPEND_ACT_COPY_LOCAL) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + return NULL; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; +} + +static void loose_data_instantiate_ensure_active_collection( + LooseDataInstantiateContext *instantiate_context) +{ + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = instantiate_context->lapp_context->params->bmain; + Scene *scene = instantiate_context->lapp_context->params->context.scene; + ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer; + + /* Find or add collection as needed. */ + if (instantiate_context->active_collection == NULL) { + if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) { + LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + instantiate_context->active_collection = lc->collection; + } + else { + if (lapp_context->params->flag & FILE_LINK) { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Linked Data")); + } + else { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Appended Data")); + } + } + } +} + +static void loose_data_instantiate_object_base_instance_init(Main *bmain, + Collection *collection, + Object *ob, + ViewLayer *view_layer, + const View3D *v3d, + const int flag, + bool set_active) +{ + /* Auto-select and appending. */ + if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) { + /* While in general the object should not be manipulated, + * when the user requests the object to be selected, ensure it's visible and selectable. */ + ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT); + } + + BKE_collection_object_add(bmain, collection, ob); + + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (v3d != NULL) { + base->local_view_bits |= v3d->local_view_uuid; + } + + if (flag & FILE_AUTOSELECT) { + /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */ + BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK)); + if (base->flag & BASE_SELECTABLE) { + base->flag |= BASE_SELECTED; + } + } + + if (set_active) { + view_layer->basact = base; + } + + BKE_scene_object_base_flag_sync_from_base(base); +} + +/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since + * the object will be instantiated instaed if needed. */ +static void loose_data_instantiate_obdata_preprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + LinkNode *itemlink; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + + id->tag |= LIB_TAG_DOIT; + } + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + Object *new_ob = (Object *)id->newid; + if (ob->data != NULL) { + ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; + } + if (new_ob != NULL && new_ob->data != NULL) { + ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; + } + } +} + +static void loose_data_instantiate_collection_process( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* NOTE: For collections we only view_layer-instantiate duplicated collections that have + * non-instantiated objects in them. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_GR) { + continue; + } + + /* We do not want to force instantiation of indirectly appended collections. Users can now + * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ + /* We need to check that objects in that collections are already instantiated in a scene. + * Otherwise, it's better to add the collection to the scene's active collection, than to + * instantiate its objects in active scene's collection directly. See T61141. + * + * NOTE: We only check object directly into that collection, not recursively into its + * children. + */ + Collection *collection = (Collection *)id; + /* We always add collections directly selected by the user. */ + bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0; + if (!do_add_collection) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + if (!object_in_any_scene(bmain, ob)) { + do_add_collection = true; + break; + } + } + } + if (!do_add_collection) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + /* In case user requested instantiation of collections as empties, we do so for the one they + * explicitly selected (originally directly linked IDs) only. */ + if ((lapp_context->params->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + /* BKE_object_add(...) messes with the selection. */ + Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); + ob->type = OB_EMPTY; + ob->empty_drawsize = U.collection_instance_empty_size; + + const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0; + /* TODO: why is it OK to make this active here but not in other situations? + * See other callers of #object_base_instance_init */ + const bool set_active = set_selected; + loose_data_instantiate_object_base_instance_init( + bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active); + + /* Assign the collection. */ + ob->instance_collection = collection; + id_us_plus(&collection->id); + ob->transflag |= OB_DUPLICOLLECTION; + copy_v3_v3(ob->loc, scene->cursor.location); + } + else { + /* Add collection as child of active collection. */ + BKE_collection_child_add(bmain, active_collection, collection); + + if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + } + } + } + } + } +} + +static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used + * anywhere. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + + if (object_in_any_collection(bmain, ob)) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + CLAMP_MIN(ob->id.us, 0); + ob->mode = OB_MODE_OBJECT; + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + } +} + +static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + if ((id->tag & LIB_TAG_DOIT) == 0) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + const int type = BKE_object_obdata_to_type(id); + BLI_assert(type != -1); + Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); + ob->data = id; + id_us_plus(id); + BKE_object_materials_test(bmain, ob, ob->data); + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + + copy_v3_v3(ob->loc, scene->cursor.location); + + id->tag &= ~LIB_TAG_DOIT; + } +} + +static void loose_data_instantiate_object_rigidbody_postprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + + LinkNode *itemlink; + /* Add rigid body objects and constraints to current RB world(s). */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + BKE_rigidbody_ensure_local_object(bmain, (Object *)id); + } +} + +static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context) +{ + if (instantiate_context->lapp_context->params->context.scene == NULL) { + /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. + */ + return; + } + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + if (do_obdata) { + loose_data_instantiate_obdata_preprocess(instantiate_context); + } + + /* First do collections, then objects, then obdata. */ + loose_data_instantiate_collection_process(instantiate_context); + loose_data_instantiate_object_process(instantiate_context); + if (do_obdata) { + loose_data_instantiate_obdata_process(instantiate_context); + } + + loose_data_instantiate_object_rigidbody_postprocess(instantiate_context); +} + +static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context, + ID *id, + BlendfileLinkAppendContextItem *item) +{ + BLI_ghash_insert(lapp_context->new_id_to_item, id, item); + + /* This ensures that if a liboverride reference is also linked/used by some other appended + * data, it gets a local copy instead of being made directly local, so that the liboverride + * references remain valid (i.e. linked data). */ + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; + } +} + +/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as + * liboverride references as already existing. */ +static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->new_id_to_item = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + new_id_to_item_mapping_add(lapp_context, id, item); + } +} + +static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data) +{ + /* NOTE: It is important to also skip liboverride references here, as those should never be made + * local. */ + if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | + IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextCallBack *data = cb_data->user_data; + ID *id = *cb_data->id_pointer; + + if (id == NULL) { + return IDWALK_RET_NOP; + } + + if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { + /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, + * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be + * processed, so we need to recursively deal with them here. */ + /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it + * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of + * shapekey referencing the shapekey itself). */ + if (id != cb_data->id_self) { + BKE_library_foreach_ID_link( + cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP); + } + return IDWALK_RET_NOP; + } + + /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation, + * so we need to add them all to the items list. + * + * In appending case, when `do_recursive` is false, we only make local IDs from same + * library(-ies) as the initially directly linked ones. + * + * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see + * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list + * completely. */ + const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0; + const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) != + 0 || + do_link; + if (!do_recursive && cb_data->id_owner->lib != id->lib) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id); + if (item == NULL) { + item = BKE_blendfile_link_append_context_item_add( + data->lapp_context, id->name, GS(id->name), NULL); + item->new_id = id; + item->source_library = id->lib; + /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, + * it was rather linked indirectly. This info is important for instantiation of collections. */ + item->tag |= LINK_APPEND_TAG_INDIRECT; + /* In linking case we already know what we want to do with those items. */ + if (do_link) { + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + new_id_to_item_mapping_add(data->lapp_context, id, item); + } + + /* NOTE: currently there is no need to do anything else here, but in the future this would be + * the place to add specific per-usage decisions on how to append an ID. */ + + return IDWALK_RET_NOP; +} + +/** \} */ + +/** \name Library link/append code. + * \{ */ + +/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, + * made local, duplicated as local, re-used from local etc. + * + * TODO: Expose somehow this logic to the two other parts of code performing actual append + * (i.e. copy/paste and `bpy` link/append API). + * Then we can heavily simplify #BKE_library_make_local(). */ +void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *bmain = lapp_context->params->bmain; + + BLI_assert((lapp_context->params->flag & FILE_LINK) == 0); + + const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; + const bool do_reuse_local_id = (lapp_context->params->flag & + BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; + + const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | + ((lapp_context->params->flag & + BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ? + LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : + 0); + + LinkNode *itemlink; + + new_id_to_item_mapping_create(lapp_context); + lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); + + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? + BKE_main_library_weak_reference_search_item( + lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name) : + NULL; + + if (item->action != LINK_APPEND_ACT_UNSET) { + /* Already set, pass. */ + } + if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + else if (do_reuse_local_id && existing_local_id != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); + item->action = LINK_APPEND_ACT_REUSE_LOCAL; + item->userdata = existing_local_id; + } + else if (id->tag & LIB_TAG_PRE_EXISTING) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); + item->action = LINK_APPEND_ACT_COPY_LOCAL; + } + else { + CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); + item->action = LINK_APPEND_ACT_MAKE_LOCAL; + } + + /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. + */ + if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link( + bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP); + } + + /* If we found a matching existing local id but are not re-using it, we need to properly clear + * its weak reference to linked data. */ + if (existing_local_id != NULL && + !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name, + existing_local_id); + } + } + + /* Effectively perform required operation on every linked ID. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + ID *local_appended_new_id = NULL; + char lib_filepath[FILE_MAX]; + BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); + char lib_id_name[MAX_ID_NAME]; + BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); + + switch (item->action) { + case LINK_APPEND_ACT_COPY_LOCAL: + BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); + local_appended_new_id = id->newid; + break; + case LINK_APPEND_ACT_MAKE_LOCAL: + BKE_lib_id_make_local(bmain, + id, + make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | + LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + BLI_assert(id->newid == NULL); + local_appended_new_id = id; + break; + case LINK_APPEND_ACT_KEEP_LINKED: + /* Nothing to do here. */ + break; + case LINK_APPEND_ACT_REUSE_LOCAL: + /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ + ID_NEW_SET(id, item->userdata); + /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ + break; + case LINK_APPEND_ACT_UNSET: + CLOG_ERROR( + &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); + break; + default: + BLI_assert(0); + } + + if (local_appended_new_id != NULL) { + if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { + BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping, + lib_filepath, + lib_id_name, + local_appended_new_id); + } + + if (set_fakeuser) { + if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { + /* Do not set fake user on objects nor collections (instancing). */ + id_fake_user_set(local_appended_new_id); + } + } + } + } + + BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping); + lapp_context->library_weak_reference_mapping = NULL; + + /* Remap IDs as needed. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action == LINK_APPEND_ACT_KEEP_LINKED) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + continue; + } + } + + BLI_assert(!ID_IS_LINKED(id)); + + BKE_libblock_relink_to_newid(bmain, id, 0); + } + + /* Remove linked IDs when a local existing data has been reused instead. */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + BLI_assert(id->newid != NULL); + + id->tag |= LIB_TAG_DOIT; + item->new_id = id->newid; + } + BKE_id_multi_tagged_delete(bmain); + + /* Instantiate newly created (duplicated) IDs as needed. */ + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + + /* Attempt to deal with object proxies. + * + * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not + * producing any useful result in any known use case), neither here nor in + * `BKE_library_make_local` currently. + * Proxies are end of life anyway, so not worth spending time on this. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_COPY_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + + /* Attempt to re-link copied proxy objects. This allows appending of an entire scene + * from another blend file into this one, even when that blend file contains proxified + * armatures that have local references. Since the proxified object needs to be linked + * (not local), this will only work when the "Localize all" checkbox is disabled. + * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ + if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { + Object *ob = (Object *)id; + Object *ob_new = (Object *)id->newid; + bool is_local = false, is_lib = false; + + /* Proxies only work when the proxified object is linked-in from a library. */ + if (!ID_IS_LINKED(ob->proxy)) { + CLOG_WARN(&LOG, + "Proxy object %s will lose its link to %s, because the " + "proxified object is local", + id->newid->name, + ob->proxy->id.name); + continue; + } + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + + /* We can only switch the proxy'ing to a made-local proxy if it is no longer + * referred to from a library. Not checking for local use; if new local proxy + * was not used locally would be a nasty bug! */ + if (is_local || is_lib) { + CLOG_WARN(&LOG, + "Made-local proxy object %s will lose its link to %s, " + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", + id->newid->name, + ob->proxy->id.name, + is_local, + is_lib); + } + else { + /* we can switch the proxy'ing from the linked-in to the made-local proxy. + * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that + * was already allocated by object_make_local() (which called BKE_object_copy). */ + ob_new->proxy = ob->proxy; + ob_new->proxy_group = ob->proxy_group; + ob_new->proxy_from = ob->proxy_from; + ob_new->proxy->proxy_from = ob_new; + ob->proxy = ob->proxy_from = ob->proxy_group = NULL; + } + } + } + + BKE_main_id_newptr_and_tag_clear(bmain); +} + +void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *mainl; + Library *lib; + + LinkNode *liblink, *itemlink; + int lib_idx, item_idx; + + BLI_assert(lapp_context->num_items && lapp_context->num_libraries); + + for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink; + lib_idx++, liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + char *libname = lib_context->path; + BlendHandle *blo_handle = link_append_context_library_blohandle_ensure( + lapp_context, lib_context, reports); + + if (blo_handle == NULL) { + /* Unlikely since we just browsed it, but possible + * Error reports will have been made by BLO_blendhandle_from_file() */ + continue; + } + + /* here appending/linking starts */ + + /* NOTE: This is temporary hotfix until whole code using link/append features has been moved to + * use new BKE code. */ + /* Do not handle instantiation in linking process anymore, we do it here in + * #loose_data_instantiate instead. */ + lapp_context->params->flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; + + mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params); + lib = mainl->curlib; + BLI_assert(lib); + UNUSED_VARS_NDEBUG(lib); + + if (mainl->versionfile < 250) { + BKE_reportf(reports, + RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation " + "conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, + mainl->subversionfile); + } + + /* For each lib file, we try to link all items belonging to that lib, + * and tag those successful to not try to load them again with the other libs. */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *new_id; + + if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { + continue; + } + + new_id = BLO_library_link_named_part( + mainl, &blo_handle, item->idcode, item->name, lapp_context->params); + + if (new_id) { + /* If the link is successful, clear item's libs 'todo' flags. + * This avoids trying to link same item with other libraries to come. */ + BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries); + item->new_id = new_id; + item->source_library = new_id->lib; + } + } + + BLO_library_link_end(mainl, &blo_handle, lapp_context->params); + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + /* Instantiate newly linked IDs as needed, if no append is scheduled. */ + if ((lapp_context->params->flag & FILE_LINK) != 0 && + lapp_context->params->context.scene != NULL) { + new_id_to_item_mapping_create(lapp_context); + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link(lapp_context->params->bmain, + id, + foreach_libblock_link_append_callback, + &cb_data, + IDWALK_NOP); + } + + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + } +} + +/** \} */ + +/** \name Library relocating code. + * \{ */ + +static void blendfile_library_relocate_remap(Main *bmain, + ID *old_id, + ID *new_id, + ReportList *reports, + const bool do_reload, + const short remap_flags) +{ + BLI_assert(old_id); + if (do_reload) { + /* Since we asked for placeholders in case of missing IDs, + * we expect to always get a valid one. */ + BLI_assert(new_id); + } + if (new_id) { + CLOG_INFO(&LOG, + 4, + "Before remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + + if (old_id->flag & LIB_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + CLOG_INFO(&LOG, + 4, + "After remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->parent = NULL; + } + } + + if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + /* Note that this *should* not happen - but better be safe than sorry in this area, + * at least until we are 100% sure this cannot ever happen. + * Also, we can safely assume names were unique so far, + * so just replacing '.' by '~' should work, + * but this does not totally rules out the possibility of name collision. */ + size_t len = strlen(old_id->name); + size_t dot_pos; + bool has_num = false; + + for (dot_pos = len; dot_pos--;) { + char c = old_id->name[dot_pos]; + if (c == '.') { + break; + } + if (c < '0' || c > '9') { + has_num = false; + break; + } + has_num = true; + } + + if (has_num) { + old_id->name[dot_pos] = '~'; + } + else { + len = MIN2(len, MAX_ID_NAME - 7); + BLI_strncpy(&old_id->name[len], "~000", 7); + } + + id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); + + BKE_reportf( + reports, + RPT_WARNING, + "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " + "old one (%d remaining users) had to be kept and was renamed to '%s'", + new_id->name, + old_id->us, + old_id->name); + } +} + +void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, + ReportList *reports, + Library *library, + const bool do_reload) +{ + ListBase *lbarray[INDEX_ID_MAX]; + int lba_idx; + + LinkNode *itemlink; + int item_idx; + + Main *bmain = lapp_context->params->bmain; + + /* Remove all IDs to be reloaded from Main. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; + + if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, + * those will get relinked with their 'users ID'. */ + continue; + } + + for (; id; id = id->next) { + if (id->lib == library) { + BlendfileLinkAppendContextItem *item; + + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ + BLI_remlink(lbarray[lba_idx], id); + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(id); + if (old_key != NULL) { + BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + + item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id); + BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries); + + CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); + } + } + } + + if (lapp_context->num_items == 0) { + /* Early out in case there is nothing to do. */ + return; + } + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instantiation here! */ + BKE_blendfile_link(lapp_context, reports); + + BKE_main_lock(bmain); + + /* We add back old id to bmain. + * We need to do this in a first, separated loop, otherwise some of those may not be handled by + * ID remapping, which means they would still reference old data to be deleted... */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + BLI_assert(old_id); + BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); + + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(old_id); + if (old_key != NULL) { + BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + } + + /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking + * code is wrong, we need to redo it here after adding them back to main. */ + BKE_main_id_refcount_recompute(bmain, false); + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | + ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | + (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + ID *new_id = item->new_id; + + blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); + if (new_id == NULL) { + continue; + } + /* Usual special code for ShapeKeys snowflakes... */ + Key **old_key_p = BKE_key_from_id_p(old_id); + if (old_key_p == NULL) { + continue; + } + Key *old_key = *old_key_p; + Key *new_key = BKE_key_from_id(new_id); + if (old_key != NULL) { + *old_key_p = NULL; + id_us_min(&old_key->id); + blendfile_library_relocate_remap( + bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); + *old_key_p = old_key; + id_us_plus_no_lib(&old_key->id); + } + } + + BKE_main_unlock(bmain); + + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + if (old_id->us == 0) { + BKE_id_free(bmain, old_id); + } + } + + /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable + * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id, *id_next; + for (id = lbarray[lba_idx]->first; id; id = id_next) { + id_next = id->next; + /* XXX That check may be a bit to generic/permissive? */ + if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { + BKE_id_free(bmain, id); + } + } + } + + /* Get rid of no more used libraries... */ + BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id; + for (id = lbarray[lba_idx]->first; id; id = id->next) { + if (id->lib) { + id->lib->id.tag &= ~LIB_TAG_DOIT; + } + } + } + Library *lib, *lib_next; + for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { + lib_next = lib->id.next; + if (lib->id.tag & LIB_TAG_DOIT) { + id_us_clear_real(&lib->id); + if (lib->id.us == 0) { + BKE_id_free(bmain, (ID *)lib); + } + } + } + + /* Update overrides of reloaded linked data-blocks. */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || + (id->tag & LIB_TAG_PRE_EXISTING) == 0) { + continue; + } + if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { + BKE_lib_override_library_update(bmain, id); + } + } + FOREACH_MAIN_ID_END; + + /* Resync overrides if needed. */ + if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { + BKE_lib_override_library_main_resync(bmain, + lapp_context->params->context.scene, + lapp_context->params->context.view_layer, + &(struct BlendFileReadReport){ + .reports = reports, + }); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); + } + + BKE_main_collection_sync(bmain); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 7d217d6907d..a682489b7cd 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -213,8 +213,9 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data) if (brush->gpencil_settings) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER); } - BKE_texture_mtex_foreach_id(data, &brush->mtex); - BKE_texture_mtex_foreach_id(data, &brush->mask_mtex); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, &brush->mask_mtex)); } static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -2474,7 +2475,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len) } /* Uses the brush curve control to find a strength value between 0 and 1 */ -float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len) +float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len) { float strength = BKE_brush_curve_strength(br, p, len); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 2dca5dcb75d..22b939d3cf9 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -716,7 +716,7 @@ Collection *BKE_collection_duplicate(Main *bmain, collection_new->id.tag &= ~LIB_TAG_NEW; /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&collection_new->id); + BKE_libblock_relink_to_newid(bmain, &collection_new->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7ddbaa0e9ee..3455baa9292 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2010,7 +2010,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* We must get compatible eulers from the beginning because * some of them can be modified below (see bug T21875). * Additionally, since this constraint is based on euler rotation math, it doesn't work well - * with shear. The Y axis is chosen as the main axis when we orthoganalize the matrix because + * with shear. The Y axis is chosen as the main axis when we orthogonalize the matrix because * constraints are used most commonly on bones. */ float mat[4][4]; copy_m4_m4(mat, ct->matrix); diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index ff0478f2543..163f8b02b85 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -109,6 +109,24 @@ void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluate } } +float CurveEval::total_length() const +{ + float length = 0.0f; + for (const SplinePtr &spline : this->splines()) { + length += spline->length(); + } + return length; +} + +int CurveEval::total_control_point_size() const +{ + int count = 0; + for (const SplinePtr &spline : this->splines()) { + count += spline->size(); + } + return count; +} + /** * Return the start indices for each of the curve spline's control points, if they were part * of a flattened array. This can be used to facilitate parallelism by avoiding the need to diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 1ef205c6903..03525e32a52 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -32,8 +32,6 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; namespace blender::bke { @@ -76,7 +74,7 @@ static void vert_extrude_to_mesh_data(const Spline &spline, Span<float3> positions = spline.evaluated_positions(); Span<float3> tangents = spline.evaluated_tangents(); Span<float3> normals = spline.evaluated_normals(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); for (const int i : IndexRange(eval_size)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i], normals[i], tangents[i]); @@ -227,7 +225,7 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info, Span<float3> normals = spline.evaluated_normals(); Span<float3> profile_positions = profile.evaluated_positions(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); for (const int i_ring : IndexRange(info.spline_vert_len)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i_ring], normals[i_ring], tangents[i_ring]); @@ -495,8 +493,8 @@ static void copy_curve_point_attribute_to_mesh(const GSpan src, const ResultInfo &info, ResultAttributeData &dst) { - GVArrayPtr interpolated_gvarray = info.spline.interpolate_to_evaluated(src); - GSpan interpolated = interpolated_gvarray->get_internal_span(); + GVArray interpolated_gvarray = info.spline.interpolate_to_evaluated(src); + GSpan interpolated = interpolated_gvarray.get_internal_span(); attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); @@ -561,8 +559,8 @@ static void copy_profile_point_attribute_to_mesh(const GSpan src, const ResultInfo &info, ResultAttributeData &dst) { - GVArrayPtr interpolated_gvarray = info.profile.interpolate_to_evaluated(src); - GSpan interpolated = interpolated_gvarray->get_internal_span(); + GVArray interpolated_gvarray = info.profile.interpolate_to_evaluated(src); + GSpan interpolated = interpolated_gvarray.get_internal_span(); attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2ef7ef91160..05f1e9b286f 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -763,7 +763,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) copy_v3_v3(bData->dim, dim); min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f; - /* deactivate zero axises */ + /* deactivate zero axes */ for (i = 0; i < 3; i++) { if (td[i] < min_dim) { td[i] = 1.0f; @@ -784,7 +784,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis); - /* define final grid size using dim_factor, use min 3 for active axises */ + /* define final grid size using dim_factor, use min 3 for active axes */ for (i = 0; i < 3; i++) { grid->dim[i] = (int)floor(td[i] / dim_factor); CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 1564eb3aa7b..bbf61c51bfb 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -205,12 +205,16 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data) FMod_Python *fcm_py = (FMod_Python *)fcm->data; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fcm_py->script, IDWALK_CB_NOP); - IDP_foreach_property(fcm_py->prop, - IDP_TYPE_FILTER_ID, - BKE_lib_query_idpropertiesForeachIDLink_callback, - data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(fcm_py->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); break; } + default: + break; } } } diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index d1bf523acef..3ac64dbf84b 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -326,7 +326,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) float(*mat[2])[4]; - /* NOTE: for now, these are all just worldspace */ + /* NOTE: for now, these are all just world-space. */ for (int i = 0; i < 2; i++) { /* Get pointer to loc values to store in. */ DriverTarget *dtar = &dvar->targets[i]; @@ -422,7 +422,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) } } else { - /* Convert to worldspace. */ + /* Convert to world-space. */ copy_v3_v3(tmp_loc, pchan->pose_head); mul_m4_v3(ob->obmat, tmp_loc); } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 6b7594dcf36..9d26a1528f3 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -5090,7 +5090,7 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, copy_v4_v4(tfds->gridlines_range_color, fds->gridlines_range_color); tfds->gridlines_cell_filter = fds->gridlines_cell_filter; - /* -- Deprecated / unsed options (below)-- */ + /* -- Deprecated / unused options (below)-- */ /* pointcache options */ BKE_ptcache_free_list(&(tfds->ptcaches[0])); diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 961265f3a16..598c61fd877 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -28,10 +28,8 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; +using blender::fn::GVArray; using blender::fn::GVArray_GSpan; -using blender::fn::GVArrayPtr; -using blender::fn::GVMutableArray_For_GMutableSpan; /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -253,15 +251,15 @@ void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve, } } -static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(curve.splines().size()); - adapt_curve_domain_point_to_spline_impl<T>(curve, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -272,29 +270,29 @@ static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVA * attributes. The goal is to avoid copying the spline value for every one of its control points * unless it is necessary (in that case the materialize functions will be called). */ -template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { - GVArrayPtr original_varray_; +template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> { + GVArray original_varray_; /* Store existing data materialized if it was not already a span. This is expected * to be worth it because a single spline's value will likely be accessed many times. */ - fn::GVArray_Span<T> original_data_; + VArray_Span<T> original_data_; Array<int> offsets_; public: - VArray_For_SplineToPoint(GVArrayPtr original_varray, Array<int> offsets) - : VArray<T>(offsets.last()), + VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets) + : VArrayImpl<T>(offsets.last()), original_varray_(std::move(original_varray)), - original_data_(*original_varray_), + original_data_(original_varray_.typed<T>()), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return original_data_[indices.spline_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { const int total_size = offsets_.last(); if (mask.is_range() && mask.as_range() == IndexRange(total_size)) { @@ -315,7 +313,7 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { T *dst = r_span.data(); const int total_size = offsets_.last(); @@ -338,29 +336,29 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } }; -static GVArrayPtr adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); Array<int> offsets = curve.control_point_offsets(); - new_varray = std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplineToPoint<T>>>( - offsets.last(), std::move(varray), std::move(offsets)); + new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray), + std::move(offsets)); }); return new_varray; } } // namespace blender::bke -GVArrayPtr CurveComponent::attribute_try_adapt_domain(GVArrayPtr varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.is_empty()) { return {}; } if (from_domain == to_domain) { @@ -402,8 +400,8 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen namespace blender::bke { class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data); - using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data); + using AsReadAttribute = GVArray (*)(const CurveEval &data); + using AsWriteAttribute = GVMutableArray (*)(CurveEval &data); const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; @@ -424,7 +422,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -483,19 +481,15 @@ static void set_spline_resolution(SplinePtr &spline, const int resolution) } } -static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve) +static GVArray make_resolution_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>( - curve.splines()); + return VArray<int>::ForDerivedSpan<SplinePtr, get_spline_resolution>(curve.splines()); } -static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve) +static GVMutableArray make_resolution_write_attribute(CurveEval &curve) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<SplinePtr, - int, - get_spline_resolution, - set_spline_resolution>>( - curve.splines()); + return VMutableArray<int>:: + ForDerivedSpan<SplinePtr, get_spline_resolution, set_spline_resolution>(curve.splines()); } static bool get_cyclic_value(const SplinePtr &spline) @@ -511,16 +505,14 @@ static void set_cyclic_value(SplinePtr &spline, const bool value) } } -static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve) +static GVArray make_cyclic_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>( - curve.splines()); + return VArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value>(curve.splines()); } -static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve) +static GVMutableArray make_cyclic_write_attribute(CurveEval &curve) { - return std::make_unique< - fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>( + return VMutableArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value, set_cyclic_value>( curve.splines()); } @@ -625,9 +617,9 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, } } -static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, - const CustomDataType data_type, - const Span<SplinePtr> splines) +static GVArray varray_from_initializer(const AttributeInit &initializer, + const CustomDataType data_type, + const Span<SplinePtr> splines) { switch (initializer.type) { case AttributeInit::Type::Default: @@ -636,16 +628,15 @@ static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, BLI_assert_unreachable(); return {}; case AttributeInit::Type::VArray: - return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy(); + return static_cast<const AttributeInitVArray &>(initializer).varray; case AttributeInit::Type::MoveArray: int total_size = 0; for (const SplinePtr &spline : splines) { total_size += spline->size(); } - return std::make_unique<fn::GVArray_For_GSpan>( - GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, - total_size)); + return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), + static_cast<const AttributeInitMove &>(initializer).data, + total_size)); } BLI_assert_unreachable(); return {}; @@ -693,11 +684,11 @@ static bool create_point_attribute(GeometryComponent &component, /* We just created the attribute, it should exist. */ BLI_assert(write_attribute); - GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, splines); + GVArray source_varray = varray_from_initializer(initializer, data_type, splines); /* TODO: When we can call a variant of #set_all with a virtual array argument, * this theoretically unnecessary materialize step could be removed. */ - GVArray_GSpan source_varray_span{*source_varray}; - write_attribute.varray->set_all(source_varray_span.data()); + GVArray_GSpan source_varray_span{source_varray}; + write_attribute.varray.set_all(source_varray_span.data()); if (initializer.type == AttributeInit::Type::MoveArray) { MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); @@ -725,29 +716,29 @@ static bool remove_point_attribute(GeometryComponent &component, /** * Virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VArray_For_SplinePoints : public VArray<T> { +template<typename T> class VArray_For_SplinePoints : public VArrayImpl<T> { private: const Array<Span<T>> data_; Array<int> offsets_; public: VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets) - : VArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize(data_.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span); } @@ -756,30 +747,30 @@ template<typename T> class VArray_For_SplinePoints : public VArray<T> { /** * Mutable virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArray<T> { +template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArrayImpl<T> { private: Array<MutableSpan<T>> data_; Array<int> offsets_; public: VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets) - : VMutableArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { const PointIndices indices = lookup_point_indices(offsets_, index); data_[indices.spline_index][indices.point_index] = value; } - void set_all_impl(Span<T> src) final + void set_all(Span<T> src) final { for (const int spline_index : data_.index_range()) { const int offset = offsets_[spline_index]; @@ -788,30 +779,28 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl } } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized( {(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } }; -template<typename T> GVArrayPtr point_data_gvarray(Array<Span<T>> spans, Array<int> offsets) +template<typename T> VArray<T> point_data_varray(Array<Span<T>> spans, Array<int> offsets) { - return std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VArray<T>::template For<VArray_For_SplinePoints<T>>(std::move(spans), std::move(offsets)); } template<typename T> -GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> offsets) +VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets) { - return std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VMutableArray<T>::template For<VMutableArray_For_SplinePoints<T>>(std::move(spans), + std::move(offsets)); } /** @@ -822,24 +811,24 @@ GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> off * \note There is no need to check the handle type to avoid changing auto handles, since * retrieving write access to the position data will mark them for recomputation anyway. */ -class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { +class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; public: VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets) - : VMutableArray<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return splines_[indices.spline_index]->positions()[indices.point_index]; } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -854,7 +843,7 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -887,21 +876,20 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { return spans; } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize(spans.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span); } }; -class VArray_For_BezierHandle final : public VArray<float3> { +class VArray_For_BezierHandle final : public VArrayImpl<float3> { private: Span<SplinePtr> splines_; Array<int> offsets_; @@ -909,7 +897,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { public: VArray_For_BezierHandle(Span<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VArray<float3>(offsets.last()), + : VArrayImpl<float3>(offsets.last()), splines_(std::move(splines)), offsets_(std::move(offsets)), is_right_(is_right) @@ -931,7 +919,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { return float3(0); } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return get_internal(index, splines_, offsets_, is_right_); } @@ -978,19 +966,18 @@ class VArray_For_BezierHandle final : public VArray<float3> { point_attribute_materialize_to_uninitialized(spans.as_span(), offsets, mask, r_span); } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_to_uninitialized_internal(mask, splines_, offsets_, is_right_, r_span); } }; -class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { +class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; @@ -1000,19 +987,19 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { VMutableArray_For_BezierHandles(MutableSpan<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VMutableArray<float3>(offsets.last()), + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)), is_right_(is_right) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return VArray_For_BezierHandle::get_internal(index, splines_, offsets_, is_right_); } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -1028,7 +1015,7 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -1051,13 +1038,12 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_to_uninitialized_internal( mask, splines_, offsets_, is_right_, r_span); @@ -1099,7 +1085,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1112,7 +1098,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu Span<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return std::make_unique<fn::GVArray_For_GSpan>(get_span_(*splines.first())); + return GVArray::ForSpan(get_span_(*splines.first())); } Array<int> offsets = curve->control_point_offsets(); @@ -1121,7 +1107,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_span_(*splines[i]); } - return point_data_gvarray(spans, offsets); + return point_data_varray(spans, offsets); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1146,8 +1132,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu MutableSpan<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return {std::make_unique<fn::GVMutableArray_For_GMutableSpan>( - get_mutable_span_(*splines.first())), + return {GVMutableArray::ForSpan(get_mutable_span_(*splines.first())), domain_, std::move(tag_modified_fn)}; } @@ -1158,7 +1143,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_mutable_span_(*splines[i]); } - return {point_data_gvarray(spans, offsets), domain_, tag_modified_fn}; + return {point_data_varray(spans, offsets), domain_, tag_modified_fn}; } bool try_delete(GeometryComponent &component) const final @@ -1250,10 +1235,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo }; Array<int> offsets = curve->control_point_offsets(); - return {std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, - VMutableArray_For_SplinePosition>>( - offsets.last(), curve->splines(), std::move(offsets)), + return {VMutableArray<float3>::For<VMutableArray_For_SplinePosition>(curve->splines(), + std::move(offsets)), domain_, tag_modified_fn}; } @@ -1275,7 +1258,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1287,8 +1270,8 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { } Array<int> offsets = curve->control_point_offsets(); - return std::make_unique<fn::GVArray_For_EmbeddedVArray<float3, VArray_For_BezierHandle>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_); + return VArray<float3>::For<VArray_For_BezierHandle>( + curve->splines(), std::move(offsets), is_right_); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1305,12 +1288,10 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); }; Array<int> offsets = curve->control_point_offsets(); - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_BezierHandles>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_), - domain_, - tag_modified_fn}; + return {VMutableArray<float3>::For<VMutableArray_For_BezierHandles>( + curve->splines(), std::move(offsets), is_right_), + domain_, + tag_modified_fn}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -1389,7 +1370,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVArray_For_GSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } ReadAttributeLookup attribute = {}; @@ -1401,7 +1382,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } @@ -1442,7 +1423,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVMutableArray_For_GMutableSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } WriteAttributeLookup attribute = {}; @@ -1454,7 +1435,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 5fe77000519..9a30c86c1e5 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -363,12 +363,22 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const int InstancesComponent::attribute_domain_size(const AttributeDomain domain) const { - if (domain != ATTR_DOMAIN_POINT) { + if (domain != ATTR_DOMAIN_INSTANCE) { return 0; } return this->instances_amount(); } +blender::bke::CustomDataAttributes &InstancesComponent::attributes() +{ + return this->attributes_; +} + +const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const +{ + return this->attributes_; +} + namespace blender::bke { static float3 get_transform_position(const float4x4 &transform) @@ -385,29 +395,26 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider public: InstancePositionAttributeProvider() : BuiltinAttributeProvider( - "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) + "position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances_component = static_cast<const InstancesComponent &>( component); Span<float4x4> transforms = instances_component.instance_transforms(); - return std::make_unique<fn::GVArray_For_DerivedSpan<float4x4, float3, get_transform_position>>( - transforms); + return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final { InstancesComponent &instances_component = static_cast<InstancesComponent &>(component); MutableSpan<float4x4> transforms = instances_component.instance_transforms(); - return { - std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4, - float3, - get_transform_position, - set_transform_position>>(transforms), - domain_}; + return {VMutableArray<float3>::ForDerivedSpan<float4x4, + get_transform_position, + set_transform_position>(transforms), + domain_}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -431,17 +438,17 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { public: InstanceIDAttributeProvider() : BuiltinAttributeProvider( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32, Creatable, Writable, Deletable) + "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances = static_cast<const InstancesComponent &>(component); if (instances.instance_ids().is_empty()) { return {}; } - return std::make_unique<fn::GVArray_For_Span<int>>(instances.instance_ids()); + return VArray<int>::ForSpan(instances.instance_ids()); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final @@ -450,8 +457,7 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { if (instances.instance_ids().is_empty()) { return {}; } - return {std::make_unique<fn::GVMutableArray_For_MutableSpan<int>>(instances.instance_ids()), - domain_}; + return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_}; } bool try_delete(GeometryComponent &component) const final @@ -477,8 +483,8 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { break; } case AttributeInit::Type::VArray: { - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), ids.data()); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), ids.data()); break; } case AttributeInit::Type::MoveArray: { @@ -503,7 +509,21 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() static InstancePositionAttributeProvider position; static InstanceIDAttributeProvider id; - return ComponentAttributeProviders({&position, &id}, {}); + static CustomDataAccessInfo instance_custom_data_access = { + [](GeometryComponent &component) -> CustomData * { + InstancesComponent &inst = static_cast<InstancesComponent &>(component); + return &inst.attributes().data; + }, + [](const GeometryComponent &component) -> const CustomData * { + const InstancesComponent &inst = static_cast<const InstancesComponent &>(component); + return &inst.attributes().data; + }, + nullptr}; + + static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE, + instance_custom_data_access); + + return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}); } } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0456316151c..a258a66cdf3 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -32,8 +32,6 @@ /* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); -using blender::fn::GVArray; - /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation * \{ */ @@ -203,17 +201,17 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { /* We compute all interpolated values at once, because for this interpolation, one has to * iterate over all loops anyway. */ Array<T> values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -239,14 +237,14 @@ static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); Array<T> values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); }); return new_varray; } @@ -295,15 +293,15 @@ void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -368,15 +366,15 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -424,15 +422,15 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -453,15 +451,15 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -507,15 +505,15 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -567,15 +565,15 @@ void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -617,15 +615,15 @@ void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -678,15 +676,15 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -728,15 +726,15 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -788,15 +786,15 @@ void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -804,15 +802,15 @@ static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr va } // namespace blender::bke -blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( - blender::fn::GVArrayPtr varray, +blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.size() == 0) { return {}; } if (from_domain == to_domain) { @@ -823,11 +821,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_CORNER: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray); default: break; } @@ -836,11 +834,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_POINT: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray); default: break; } @@ -849,11 +847,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_FACE: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray); default: break; } @@ -862,11 +860,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_EDGE: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray); default: break; } @@ -896,9 +894,9 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com namespace blender::bke { template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size) +static GVArray make_derived_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( + return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>( Span<StructT>((const StructT *)data, domain_size)); } @@ -906,23 +904,22 @@ template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, ElemT)> -static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size) +static GVMutableArray make_derived_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>( + return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>( MutableSpan<StructT>((StructT *)data, domain_size)); } template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } static float3 get_vertex_position(const MVert &vert) @@ -999,23 +996,23 @@ static void set_crease(MEdge &edge, float value) edge.crease = round_fl_to_uchar_clamp(value * 255.0f); } -class VMutableArray_For_VertexWeights final : public VMutableArray<float> { +class VMutableArray_For_VertexWeights final : public VMutableArrayImpl<float> { private: MDeformVert *dverts_; const int dvert_index_; public: VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index) - : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return get_internal(dverts_, dvert_index_, index); } - void set_impl(const int64_t index, const float value) override + void set(const int64_t index, const float value) override { MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); weight->weight = value; @@ -1036,18 +1033,18 @@ class VMutableArray_For_VertexWeights final : public VMutableArray<float> { } }; -class VArray_For_VertexWeights final : public VArray<float> { +class VArray_For_VertexWeights final : public VArrayImpl<float> { private: const MDeformVert *dverts_; const int dvert_index_; public: VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index) - : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index); } @@ -1078,12 +1075,10 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { } if (mesh->dvert == nullptr) { static const float default_value = 0.0f; - return {std::make_unique<fn::GVArray_For_SingleValueRef>( - CPPType::get<float>(), mesh->totvert, &default_value), - ATTR_DOMAIN_POINT}; + return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT}; } - return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), + return {VArray<float>::For<VArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), ATTR_DOMAIN_POINT}; } @@ -1114,11 +1109,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); } - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), - ATTR_DOMAIN_POINT}; + return {VMutableArray<float>::For<VMutableArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), + ATTR_DOMAIN_POINT}; } bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final @@ -1187,7 +1180,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); @@ -1200,8 +1193,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, mesh->totpoly)); + return VArray<float3>::ForSpan(Span<float3>((const float3 *)data, mesh->totpoly)); } Array<float3> normals(mesh->totpoly); @@ -1210,7 +1202,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); } - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index dfb65a9078d..c6a1c61a96d 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -141,16 +141,15 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con namespace blender::bke { template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } /** diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index cd1bafe445a..c250c14f1d7 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -610,24 +610,32 @@ bool BKE_object_has_geometry_set_instances(const Object *ob) if (geometry_set == nullptr) { return false; } - if (geometry_set->has_instances()) { - return true; - } - const bool has_mesh = geometry_set->has_mesh(); - const bool has_pointcloud = geometry_set->has_pointcloud(); - const bool has_volume = geometry_set->has_volume(); - const bool has_curve = geometry_set->has_curve(); - if (ob->type == OB_MESH) { - return has_pointcloud || has_volume || has_curve; - } - if (ob->type == OB_POINTCLOUD) { - return has_mesh || has_volume || has_curve; - } - if (ob->type == OB_VOLUME) { - return has_mesh || has_pointcloud || has_curve; - } - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - return has_mesh || has_pointcloud || has_volume; + for (const GeometryComponent *component : geometry_set->get_components_for_read()) { + if (component->is_empty()) { + continue; + } + const GeometryComponentType type = component->type(); + bool is_instance = false; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: + is_instance = ob->type != OB_MESH; + break; + case GEO_COMPONENT_TYPE_POINT_CLOUD: + is_instance = ob->type != OB_POINTCLOUD; + break; + case GEO_COMPONENT_TYPE_INSTANCES: + is_instance = true; + break; + case GEO_COMPONENT_TYPE_VOLUME: + is_instance = ob->type != OB_VOLUME; + break; + case GEO_COMPONENT_TYPE_CURVE: + is_instance = !ELEM(ob->type, OB_CURVE, OB_FONT); + break; + } + if (is_instance) { + return true; + } } return false; } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 8a7840acd73..c73da7d9659 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -89,8 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) static void geometry_set_collect_recursive_collection_instance( const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets) { - float4x4 offset_matrix; - unit_m4(offset_matrix.values); + float4x4 offset_matrix = float4x4::identity(); sub_v3_v3(offset_matrix.values[3], collection.instance_offset); const float4x4 instance_transform = transform * offset_matrix; geometry_set_collect_recursive_collection(collection, instance_transform, r_sets); @@ -183,10 +182,7 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector<GeometryInstanceGroup> &r_instance_groups) { - float4x4 unit_transform; - unit_m4(unit_transform.values); - - geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups); + geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups); } void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups, @@ -364,12 +360,12 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, result.attribute_try_create( entry.key, domain_output, data_type_output, AttributeInitDefault()); WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id); - if (!write_attribute || &write_attribute.varray->type() != cpp_type || + if (!write_attribute || &write_attribute.varray.type() != cpp_type || write_attribute.domain != domain_output) { continue; } - fn::GVMutableArray_GSpan dst_span{*write_attribute.varray}; + fn::GVMutableArray_GSpan dst_span{write_attribute.varray}; int offset = 0; for (const GeometryInstanceGroup &set_group : set_groups) { @@ -381,11 +377,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, if (domain_size == 0) { continue; /* Domain size is 0, so no need to increment the offset. */ } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( attribute_id, domain_output, data_type_output); if (source_attribute) { - fn::GVArray_GSpan src_span{*source_attribute}; + fn::GVArray_GSpan src_span{source_attribute}; const void *src_buffer = src_span.data(); for (const int UNUSED(i) : set_group.transforms.index_range()) { void *dst_buffer = dst_span[offset]; diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index debdf44b0bb..fffc13c49a8 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -3122,8 +3122,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit) + const bool select, + const bool flat_cap, + const int limit) { tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN( sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); @@ -3171,6 +3172,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, for (idx = 0; idx < num_islands; idx++) { tGPDeleteIsland *island = &islands[idx]; new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); + if (flat_cap) { + new_stroke->caps[1 - (idx % 2)] = GP_STROKE_CAP_FLAT; + } /* if cyclic and first stroke, save to join later */ if ((is_cyclic) && (gps_first == nullptr)) { diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 9cf289935ab..c2250dd04f9 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -35,6 +35,7 @@ #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -375,6 +376,7 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_SCE, Scene); ID_PRV_CASE(ID_SCR, bScreen); ID_PRV_CASE(ID_AC, bAction); + ID_PRV_CASE(ID_NT, bNodeTree); #undef ID_PRV_CASE default: break; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0530d537daf..1ef5659855b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -112,12 +112,26 @@ #include "DNA_view3d_types.h" static CLG_LogRef LOG = {"bke.image"}; -static ThreadMutex *image_mutex; static void image_init(Image *ima, short source, short type); static void image_free_packedfiles(Image *ima); static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src); +/* Reset runtime image fields when datablock is being initialized. */ +static void image_runtime_reset(struct Image *image) +{ + memset(&image->runtime, 0, sizeof(image->runtime)); + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + +/* Reset runtime image fields when datablock is being copied. */ +static void image_runtime_reset_on_copy(struct Image *image) +{ + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + static void image_init_data(ID *id) { Image *image = (Image *)id; @@ -167,6 +181,8 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c else { image_dst->preview = NULL; } + + image_runtime_reset_on_copy(image_dst); } static void image_free_data(ID *id) @@ -194,6 +210,9 @@ static void image_free_data(ID *id) BLI_freelistN(&image->tiles); BLI_freelistN(&image->gpu_refresh_areas); + + BLI_mutex_end(image->runtime.cache_mutex); + MEM_freeN(image->runtime.cache_mutex); } static void image_foreach_cache(ID *id, @@ -325,6 +344,8 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) ima->lastused = 0; ima->gpuflag = 0; BLI_listbase_clear(&ima->gpu_refresh_areas); + + image_runtime_reset(ima); } static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) @@ -452,16 +473,6 @@ static struct ImBuf *imagecache_get(Image *image, int index, bool *r_is_cached_e return NULL; } -void BKE_images_init(void) -{ - image_mutex = BLI_mutex_alloc(); -} - -void BKE_images_exit(void) -{ - BLI_mutex_free(image_mutex); -} - /* ***************** ALLOC & FREE, DATA MANAGING *************** */ static void image_free_cached_frames(Image *image) @@ -514,7 +525,7 @@ static void image_free_anims(Image *ima) void BKE_image_free_buffers_ex(Image *ima, bool do_lock) { if (do_lock) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); } image_free_cached_frames(ima); @@ -528,7 +539,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock) BKE_image_free_gputextures(ima); if (do_lock) { - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -567,6 +578,8 @@ static void image_init(Image *ima, short source, short type) } } + image_runtime_reset(ima); + BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings); ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format"); } @@ -640,7 +653,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) { /* sanity check */ if (dest && source && dest != source) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(source->runtime.cache_mutex); + BLI_mutex_lock(dest->runtime.cache_mutex); + if (source->cache != NULL) { struct MovieCacheIter *iter; iter = IMB_moviecacheIter_new(source->cache); @@ -652,7 +667,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(dest->runtime.cache_mutex); + BLI_mutex_unlock(source->runtime.cache_mutex); BKE_id_free(bmain, source); } @@ -1243,7 +1260,8 @@ static uintptr_t image_mem_size(Image *image) return 0; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); + if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -1277,7 +1295,8 @@ static uintptr_t image_mem_size(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(image->runtime.cache_mutex); return size; } @@ -1361,11 +1380,11 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void /* except_frame is weak, only works for seqs without offset... */ void BKE_image_free_anim_ibufs(Image *ima, int except_frame) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); if (ima->cache != NULL) { IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra) @@ -3284,7 +3303,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * } if (do_reset) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); image_free_cached_frames(ima); BKE_image_free_views(ima); @@ -3292,7 +3311,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * /* add new views */ image_viewer_create_views(rd, ima); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } BLI_thread_unlock(LOCK_DRAW_IMAGE); @@ -3556,7 +3575,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) return; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); switch (signal) { case IMA_SIGNAL_FREE: @@ -3676,7 +3695,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) break; } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); /* don't use notifiers because they are not 100% sure to succeeded * this also makes sure all scenes are accounted for. */ @@ -5130,11 +5149,11 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_acquire_ibuf(ima, iuser, r_lock); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); return ibuf; } @@ -5153,9 +5172,9 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock) } if (ibuf) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -5169,7 +5188,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) return false; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL, NULL); @@ -5177,7 +5196,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) ibuf = image_acquire_ibuf(ima, iuser, NULL); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); @@ -5197,6 +5216,7 @@ typedef struct ImagePoolItem { typedef struct ImagePool { ListBase image_buffers; BLI_mempool *memory_pool; + ThreadMutex mutex; } ImagePool; ImagePool *BKE_image_pool_new(void) @@ -5204,21 +5224,28 @@ ImagePool *BKE_image_pool_new(void) ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool"); pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP); + BLI_mutex_init(&pool->mutex); + return pool; } void BKE_image_pool_free(ImagePool *pool) { /* Use single lock to dereference all the image buffers. */ - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(&pool->mutex); for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) { if (item->ibuf != NULL) { + BLI_mutex_lock(item->image->runtime.cache_mutex); IMB_freeImBuf(item->ibuf); + BLI_mutex_unlock(item->image->runtime.cache_mutex); } } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); BLI_mempool_destroy(pool->memory_pool); + + BLI_mutex_end(&pool->mutex); + MEM_freeN(pool); } @@ -5250,28 +5277,34 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool } if (pool == NULL) { - /* pool could be NULL, in this case use general acquire function */ + /* Pool could be NULL, in this case use general acquire function. */ return BKE_image_acquire_ibuf(ima, iuser, NULL); } image_get_entry_and_index(ima, iuser, &entry, &index); + /* Use double-checked locking, to avoid locking when the requested image buffer is already in the + * pool. */ + ibuf = image_pool_find_item(pool, ima, entry, index, &found); if (found) { return ibuf; } - BLI_mutex_lock(image_mutex); + /* Lock the pool, to allow thread-safe modification of the content of the pool. */ + BLI_mutex_lock(&pool->mutex); ibuf = image_pool_find_item(pool, ima, entry, index, &found); - /* will also create item even in cases image buffer failed to load, - * prevents trying to load the same buggy file multiple times - */ + /* Will also create item even in cases image buffer failed to load, + * prevents trying to load the same buggy file multiple times. */ if (!found) { ImagePoolItem *item; - ibuf = image_acquire_ibuf(ima, iuser, NULL); + /* Thread-safe acquisition of an image buffer from the image. + * The acquisition does not use image pools, so there is no risk of recursive or out-of-order + * mutex locking. */ + ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); item = BLI_mempool_alloc(pool->memory_pool); item->image = ima; @@ -5282,7 +5315,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool BLI_addtail(&pool->image_buffers, item); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); return ibuf; } @@ -5671,7 +5704,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) bool is_dirty = false; bool is_writable = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5686,7 +5719,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); if (r_is_writable) { *r_is_writable = is_writable; @@ -5715,7 +5748,7 @@ bool BKE_image_buffer_format_writable(ImBuf *ibuf) void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5729,14 +5762,14 @@ void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions * } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); } bool BKE_image_has_loaded_ibuf(Image *image) { bool has_loaded_ibuf = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5746,7 +5779,7 @@ bool BKE_image_has_loaded_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return has_loaded_ibuf; } @@ -5759,7 +5792,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5774,7 +5807,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } @@ -5792,7 +5825,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5805,7 +5838,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 943909cc90f..bef14b6ad70 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -369,7 +369,7 @@ static void checker_board_text( char text[3] = {'A', '1', '\0'}; const int mono = blf_mono_font_render; - BLF_size(mono, 54, 72); /* hard coded size! */ + BLF_size(mono, 54.0f, 72); /* hard coded size! */ /* OCIO_TODO: using NULL as display will assume using sRGB display * this is correct since currently generated images are assumed to be in sRGB space, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 9ed7218027f..66a550ec6b0 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1028,7 +1028,7 @@ static void lib_override_library_proxy_convert_do(Main *bmain, if (success) { CLOG_INFO(&LOG, 4, - "Proxy object '%s' successfuly converted to library overrides", + "Proxy object '%s' successfully converted to library overrides", ob_proxy->id.name); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4165452801c..74750a9b61a 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -76,48 +76,52 @@ typedef struct LibraryForeachIDData { BLI_LINKSTACK_DECLARE(ids_todo, ID *); } LibraryForeachIDData; -bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +/** Check whether current iteration over ID usages should be stopped or not. + * \return true if the iteration should be stopped, false otherwise. */ +bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data) { - if (!(data->status & IDWALK_STOP)) { - const int flag = data->flag; - ID *old_id = *id_pp; - - /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic - * caller code. */ - cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); - - /* Update the callback flags with some extra information regarding overrides: all 'loopback', - * 'internal', 'embedded' etc. ID pointers are never overridable. */ - if (cb_flag & - (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; - } + return (data->status & IDWALK_STOP) != 0; +} - const int callback_return = data->callback( - &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, - .bmain = data->bmain, - .id_owner = data->owner_id, - .id_self = data->self_id, - .id_pointer = id_pp, - .cb_flag = cb_flag}); - if (flag & IDWALK_READONLY) { - BLI_assert(*(id_pp) == old_id); - } - if (old_id && (flag & IDWALK_RECURSE)) { - if (BLI_gset_add((data)->ids_handled, old_id)) { - if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { - BLI_LINKSTACK_PUSH(data->ids_todo, old_id); - } +void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +{ + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; + } + + const int flag = data->flag; + ID *old_id = *id_pp; + + /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic + * caller code. */ + cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); + + /* Update the callback flags with some extra information regarding overrides: all 'loopback', + * 'internal', 'embedded' etc. ID pointers are never overridable. */ + if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; + } + + const int callback_return = data->callback( + &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, + .bmain = data->bmain, + .id_owner = data->owner_id, + .id_self = data->self_id, + .id_pointer = id_pp, + .cb_flag = cb_flag}); + if (flag & IDWALK_READONLY) { + BLI_assert(*(id_pp) == old_id); + } + if (old_id && (flag & IDWALK_RECURSE)) { + if (BLI_gset_add((data)->ids_handled, old_id)) { + if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { + BLI_LINKSTACK_PUSH(data->ids_todo, old_id); } } - if (callback_return & IDWALK_RET_STOP_ITER) { - data->status |= IDWALK_STOP; - return false; - } - return true; } - - return false; + if (callback_return & IDWALK_RET_STOP_ITER) { + data->status |= IDWALK_STOP; + } } int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data) @@ -139,7 +143,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData return cb_flag_backup; } -static void library_foreach_ID_link(Main *bmain, +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -158,19 +162,24 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag); } -bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) +/** Process embedded ID pointers (root nodetrees, master collections, ...). + * + * Those require specific care, since they are technically sub-data of their owner, yet in some + * cases they still behave as regular IDs. */ +void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { /* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */ ID *id = *id_pp; const int flag = data->flag; - if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) { - return false; + BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED); + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; } BLI_assert(id == *id_pp); if (id == NULL) { - return true; + return; } if (flag & IDWALK_IGNORE_EMBEDDED_ID) { @@ -186,14 +195,24 @@ bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) } } else { - library_foreach_ID_link( - data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data); + if (!library_foreach_ID_link( + data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data)) { + data->status |= IDWALK_STOP; + return; + } } +} - return true; +static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data) +{ + if (data->ids_handled != NULL) { + BLI_gset_free(data->ids_handled, NULL); + BLI_LINKSTACK_FREE(data->ids_todo); + } } -static void library_foreach_ID_link(Main *bmain, +/** \return false in case iteration over ID pointers must be stopped, true otherwise. */ +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -210,6 +229,10 @@ static void library_foreach_ID_link(Main *bmain, flag |= IDWALK_READONLY; flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS; + /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set, + * see also comments in #BKE_library_foreach_ID_embedded. + * This is why we can always create this data here, and do not need to try and re-use it from + * `inherit_data`. */ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); BLI_LINKSTACK_INIT(data.ids_todo); @@ -224,10 +247,26 @@ static void library_foreach_ID_link(Main *bmain, data.user_data = user_data; #define CALLBACK_INVOKE_ID(check_id, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag) + { \ + CHECK_TYPE_ANY((check_id), ID *, void *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) #define CALLBACK_INVOKE(check_id_super, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_IDSUPER(&data, check_id_super, cb_flag) + { \ + CHECK_TYPE(&((check_id_super)->id), ID *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; @@ -269,6 +308,10 @@ static void library_foreach_ID_link(Main *bmain, to_id_entry = to_id_entry->next) { BKE_lib_query_foreachid_process( &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } continue; } @@ -292,26 +335,33 @@ static void library_foreach_ID_link(Main *bmain, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } AnimData *adt = BKE_animdata_from_id(id); if (adt) { BKE_animdata_foreach_id(adt, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); if (id_type->foreach_id != NULL) { id_type->foreach_id(id, &data); - if (data.status & IDWALK_STOP) { - break; + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; } } } - if (data.ids_handled) { - BLI_gset_free(data.ids_handled, NULL); - BLI_LINKSTACK_FREE(data.ids_todo); - } + library_foreach_ID_data_cleanup(&data); + return true; #undef CALLBACK_INVOKE_ID #undef CALLBACK_INVOKE diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 905ac5af512..014c923f04f 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -132,7 +132,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) const bool is_obj = (GS(id_owner->name) == ID_OB); const bool is_obj_proxy = (is_obj && (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); - const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) && + (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; @@ -669,57 +670,10 @@ void BKE_libblock_relink_ex( DEG_relations_tag_update(bmain); } +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag); static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_EMBEDDED) { - return IDWALK_RET_NOP; - } - - ID **id_pointer = cb_data->id_pointer; - ID *id = *id_pointer; - if (id) { - /* See: NEW_ID macro */ - if (id->newid) { - BKE_library_update_ID_link_user(id->newid, id, cb_flag); - id = id->newid; - *id_pointer = id; - } - if (id->tag & LIB_TAG_NEW) { - id->tag &= ~LIB_TAG_NEW; - BKE_libblock_relink_to_newid(id); - } - } - return IDWALK_RET_NOP; -} - -/** - * Similar to #libblock_relink_ex, - * but is remapping IDs to their newid value if non-NULL, in given \a id. - * - * Very specific usage, not sure we'll keep it on the long run, - * currently only used in Object/Collection duplication code... - * - * WARNING: This is a deprecated version of this function, should not be used by new code. See - * #BKE_libblock_relink_to_newid_new below. - */ -void BKE_libblock_relink_to_newid(ID *id) -{ - if (ID_IS_LINKED(id)) { - return; - } - - BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0); -} - -/* ************************ - * FIXME: Port all usages of #BKE_libblock_relink_to_newid to this - * #BKE_libblock_relink_to_newid_new new code and remove old one. - ************************** */ -static void libblock_relink_to_newid_new(Main *bmain, ID *id); -static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) -{ - const int cb_flag = cb_data->cb_flag; if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { return IDWALK_RET_NOP; } @@ -729,31 +683,31 @@ static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) ID **id_pointer = cb_data->id_pointer; ID *id = *id_pointer; if (id) { + const int remap_flag = POINTER_AS_INT(cb_data->user_data); /* See: NEW_ID macro */ if (id->newid != NULL) { - BKE_libblock_relink_ex(bmain, - id_owner, - id, - id->newid, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE | + ID_REMAP_SKIP_OVERRIDE_LIBRARY; + BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, (short)remap_flag_final); id = id->newid; } if (id->tag & LIB_TAG_NEW) { id->tag &= ~LIB_TAG_NEW; - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); } } return IDWALK_RET_NOP; } -static void libblock_relink_to_newid_new(Main *bmain, ID *id) +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; } id->tag &= ~LIB_TAG_NEW; - BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper_new, NULL, 0); + BKE_library_foreach_ID_link( + bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0); } /** @@ -765,7 +719,7 @@ static void libblock_relink_to_newid_new(Main *bmain, ID *id) * Very specific usage, not sure we'll keep it on the long run, * currently only used in Object/Collection duplication code... */ -void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) +void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; @@ -774,7 +728,7 @@ void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) BLI_assert(bmain->relations == NULL); BKE_layer_collection_resync_forbid(); - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); BKE_layer_collection_resync_allow(); BKE_main_collection_sync_remap(bmain); } diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index a6150028f46..05e8d4fe978 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -129,7 +129,8 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data) Light *lamp = (Light *)id; if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree)); } } diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index a1c93920731..3c305d1fb3f 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -155,12 +155,14 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (linestyle->mtex[i]) { - BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_texture_mtex_foreach_id(data, linestyle->mtex[i])); } } if (linestyle->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree)); } LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index d82559a27cb..1fac83c5665 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -166,9 +166,8 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data) { Material *material = (Material *)id; /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ - if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) { - return; - } + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)); if (material->texpaintslot != NULL) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP); } @@ -903,7 +902,7 @@ void BKE_object_materials_test(Main *bmain, Object *ob, ID *id) if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) { /* Exception: In case the object is a valid data, but its obdata is an empty place-holder, * use object's material slots amount as reference. - * This avoids loosing materials in a local object when its linked obdata gets missing. + * This avoids losing materials in a local object when its linked obdata goes missing. * See T92780. */ BKE_id_material_resize(bmain, id, (short)ob->totcol, false); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.cc index f0ba83b396b..73e0c2cfa74 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.cc @@ -124,7 +124,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); } - mesh_dst->mat = MEM_dupallocN(mesh_src->mat); + mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat); BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); @@ -142,9 +142,9 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); - mesh_dst->edit_mesh = NULL; + mesh_dst->edit_mesh = nullptr; - mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect); + mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect); /* TODO: Do we want to add flag to prevent this? */ if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { @@ -165,7 +165,7 @@ static void mesh_free_data(ID *id) BKE_editmesh_free_data(mesh->edit_mesh); } MEM_freeN(mesh->edit_mesh); - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; } BKE_mesh_runtime_free_data(mesh); @@ -188,14 +188,14 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); - CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; /* cache only - don't write */ - mesh->mface = NULL; + mesh->mface = nullptr; mesh->totface = 0; memset(&mesh->fdata, 0, sizeof(mesh->fdata)); memset(&mesh->runtime, 0, sizeof(mesh->runtime)); @@ -203,22 +203,22 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address /* Do not store actual geometry data in case this is a library override ID. */ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { - mesh->mvert = NULL; + mesh->mvert = nullptr; mesh->totvert = 0; memset(&mesh->vdata, 0, sizeof(mesh->vdata)); vlayers = vlayers_buff; - mesh->medge = NULL; + mesh->medge = nullptr; mesh->totedge = 0; memset(&mesh->edata, 0, sizeof(mesh->edata)); elayers = elayers_buff; - mesh->mloop = NULL; + mesh->mloop = nullptr; mesh->totloop = 0; memset(&mesh->ldata, 0, sizeof(mesh->ldata)); llayers = llayers_buff; - mesh->mpoly = NULL; + mesh->mpoly = nullptr; mesh->totpoly = 0; memset(&mesh->pdata, 0, sizeof(mesh->pdata)); players = players_buff; @@ -307,13 +307,13 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; memset(&mesh->runtime, 0, sizeof(mesh->runtime)); BKE_mesh_runtime_init_data(mesh); /* happens with old files */ - if (mesh->mselect == NULL) { + if (mesh->mselect == nullptr) { mesh->totselect = 0; } @@ -355,31 +355,28 @@ static void mesh_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_ME = { - .id_code = ID_ME, - .id_filter = FILTER_ID_ME, - .main_listbase_index = INDEX_ID_ME, - .struct_size = sizeof(Mesh), - .name = "Mesh", - .name_plural = "meshes", - .translation_context = BLT_I18NCONTEXT_ID_MESH, - .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, - - .init_data = mesh_init_data, - .copy_data = mesh_copy_data, - .free_data = mesh_free_data, - .make_local = NULL, - .foreach_id = mesh_foreach_id, - .foreach_cache = NULL, - .owner_get = NULL, - - .blend_write = mesh_blend_write, - .blend_read_data = mesh_blend_read_data, - .blend_read_lib = mesh_blend_read_lib, - .blend_read_expand = mesh_read_expand, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + ID_ME, + FILTER_ID_ME, + INDEX_ID_ME, + sizeof(Mesh), + "Mesh", + "meshes", + BLT_I18NCONTEXT_ID_MESH, + IDTYPE_FLAGS_APPEND_IS_REUSABLE, + + mesh_init_data, + mesh_copy_data, + mesh_free_data, + nullptr, + mesh_foreach_id, + nullptr, + nullptr, + mesh_blend_write, + mesh_blend_read_data, + mesh_blend_read_lib, + mesh_read_expand, + nullptr, + nullptr, }; enum { @@ -471,8 +468,8 @@ static int customdata_compare( switch (l1->type) { case CD_MVERT: { - MVert *v1 = l1->data; - MVert *v2 = l2->data; + MVert *v1 = (MVert *)l1->data; + MVert *v2 = (MVert *)l2->data; int vtot = m1->totvert; for (j = 0; j < vtot; j++, v1++, v2++) { @@ -488,8 +485,8 @@ static int customdata_compare( /* We're order-agnostic for edges here. */ case CD_MEDGE: { - MEdge *e1 = l1->data; - MEdge *e2 = l2->data; + MEdge *e1 = (MEdge *)l1->data; + MEdge *e2 = (MEdge *)l2->data; int etot = m1->totedge; EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); @@ -502,12 +499,12 @@ static int customdata_compare( return MESHCMP_EDGEUNKNOWN; } } - BLI_edgehash_free(eh, NULL); + BLI_edgehash_free(eh, nullptr); break; } case CD_MPOLY: { - MPoly *p1 = l1->data; - MPoly *p2 = l2->data; + MPoly *p1 = (MPoly *)l1->data; + MPoly *p2 = (MPoly *)l2->data; int ptot = m1->totpoly; for (j = 0; j < ptot; j++, p1++, p2++) { @@ -530,8 +527,8 @@ static int customdata_compare( break; } case CD_MLOOP: { - MLoop *lp1 = l1->data; - MLoop *lp2 = l2->data; + MLoop *lp1 = (MLoop *)l1->data; + MLoop *lp2 = (MLoop *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -542,8 +539,8 @@ static int customdata_compare( break; } case CD_MLOOPUV: { - MLoopUV *lp1 = l1->data; - MLoopUV *lp2 = l2->data; + MLoopUV *lp1 = (MLoopUV *)l1->data; + MLoopUV *lp2 = (MLoopUV *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -554,8 +551,8 @@ static int customdata_compare( break; } case CD_MLOOPCOL: { - MLoopCol *lp1 = l1->data; - MLoopCol *lp2 = l2->data; + MLoopCol *lp1 = (MLoopCol *)l1->data; + MLoopCol *lp2 = (MLoopCol *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -566,8 +563,8 @@ static int customdata_compare( break; } case CD_MDEFORMVERT: { - MDeformVert *dv1 = l1->data; - MDeformVert *dv2 = l2->data; + MDeformVert *dv1 = (MDeformVert *)l1->data; + MDeformVert *dv2 = (MDeformVert *)l2->data; int dvtot = m1->totvert; for (j = 0; j < dvtot; j++, dv1++, dv2++) { @@ -590,8 +587,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT: { - const float *l1_data = l1->data; - const float *l2_data = l2->data; + const float *l1_data = (float *)l1->data; + const float *l2_data = (float *)l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { @@ -601,8 +598,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT2: { - const float(*l1_data)[2] = l1->data; - const float(*l2_data)[2] = l2->data; + const float(*l1_data)[2] = (float(*)[2])l1->data; + const float(*l2_data)[2] = (float(*)[2])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -615,8 +612,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT3: { - const float(*l1_data)[3] = l1->data; - const float(*l2_data)[3] = l2->data; + const float(*l1_data)[3] = (float(*)[3])l1->data; + const float(*l2_data)[3] = (float(*)[3])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -632,8 +629,8 @@ static int customdata_compare( break; } case CD_PROP_INT32: { - const int *l1_data = l1->data; - const int *l2_data = l2->data; + const int *l1_data = (int *)l1->data; + const int *l2_data = (int *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -643,8 +640,8 @@ static int customdata_compare( break; } case CD_PROP_BOOL: { - const bool *l1_data = l1->data; - const bool *l2_data = l2->data; + const bool *l1_data = (bool *)l1->data; + const bool *l2_data = (bool *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -654,8 +651,8 @@ static int customdata_compare( break; } case CD_PROP_COLOR: { - const MPropCol *l1_data = l1->data; - const MPropCol *l2_data = l2->data; + const MPropCol *l1_data = (MPropCol *)l1->data; + const MPropCol *l2_data = (MPropCol *)l2->data; for (int i = 0; i < total_length; i++) { for (j = 0; j < 4; j++) { @@ -722,7 +719,7 @@ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) return cmpcode_to_str(c); } - return NULL; + return nullptr; } static void mesh_ensure_tessellation_customdata(Mesh *me) @@ -767,7 +764,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) void BKE_mesh_ensure_skin_customdata(Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; MVertSkin *vs; if (bm) { @@ -779,7 +776,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) /* Mark an arbitrary vertex as root */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); + vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); vs->flag |= MVERT_SKIN_ROOT; break; } @@ -787,7 +784,8 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) } else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { - vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert); + vs = (MVertSkin *)CustomData_add_layer( + &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -799,7 +797,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -809,7 +807,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -818,7 +816,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -836,12 +834,12 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) } /** - * This ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or - * mloopcol and mcol) have the same relative active/render/clone/mask indices. + * This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or + * #CD_MLOOPCOL and #CD_MCOL) have the same relative active/render/clone/mask indices. * - * NOTE(campbell): that for undo mesh data we want to skip 'ensure_tess_cd' call since - * we don't want to store memory for tessface when its only used for older - * Versions of the mesh. + * NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since + * we don't want to store memory for #MFace data when its only used for older + * versions of the mesh. */ static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) { @@ -856,20 +854,20 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) { mesh_update_linked_customdata(me, do_ensure_tess_cd); - me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); - me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT); + me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE); - me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); - me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); - me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); + me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE); + me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL); + me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE); - me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); - me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY); + me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP); - me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); - me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); + me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL); + me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV); } bool BKE_mesh_has_custom_loop_normals(Mesh *me) @@ -883,7 +881,7 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) /** * Free (or release) any data used by this mesh (does not free the mesh itself). - * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used. + * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used. */ void BKE_mesh_free_data_for_undo(Mesh *me) { @@ -939,15 +937,15 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) CustomData_reset(&mesh->fdata); } - mesh->mface = NULL; - mesh->mtface = NULL; - mesh->mcol = NULL; + mesh->mface = nullptr; + mesh->mtface = nullptr; + mesh->mcol = nullptr; mesh->totface = 0; } Mesh *BKE_mesh_add(Main *bmain, const char *name) { - Mesh *me = BKE_id_new(bmain, ID_ME, name); + Mesh *me = (Mesh *)BKE_id_new(bmain, ID_ME, name); return me; } @@ -956,28 +954,28 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); } } Mesh *BKE_mesh_new_nomain( int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) { - Mesh *mesh = BKE_libblock_alloc( - NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); + Mesh *mesh = (Mesh *)BKE_libblock_alloc( + nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); BKE_libblock_init_empty(&mesh->id); /* Don't use #CustomData_reset because we don't want to touch custom-data. */ @@ -1043,10 +1041,10 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); /* Copy materials. */ - if (me_dst->mat != NULL) { + if (me_dst->mat != nullptr) { MEM_freeN(me_dst->mat); } - me_dst->mat = MEM_dupallocN(me_src->mat); + me_dst->mat = (Material **)MEM_dupallocN(me_src->mat); me_dst->totcol = me_src->totcol; } @@ -1061,9 +1059,9 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); - Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); + Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - me_dst->mselect = MEM_dupallocN(me_src->mselect); + me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); me_dst->totvert = verts_len; me_dst->totedge = edges_len; @@ -1107,7 +1105,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src, void BKE_mesh_eval_delete(struct Mesh *mesh_eval) { /* Evaluated mesh may point to edit mesh, but never owns it. */ - mesh_eval->edit_mesh = NULL; + mesh_eval->edit_mesh = nullptr; mesh_free_data(&mesh_eval->id); BKE_libblock_free_data(&mesh_eval->id, false); MEM_freeN(mesh_eval); @@ -1121,7 +1119,7 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) flags |= LIB_ID_COPY_CD_REFERENCE; } - Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags); + Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); return result; } @@ -1142,14 +1140,12 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, const bool add_key_index, const struct BMeshCreateParams *params) { - return BKE_mesh_to_bmesh_ex(me, - params, - &(struct BMeshFromMeshParams){ - .calc_face_normal = false, - .add_key_index = add_key_index, - .use_shapekey = true, - .active_shapekey = ob->shapenr, - }); + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = false; + bmesh_from_mesh_params.add_key_index = add_key_index; + bmesh_from_mesh_params.use_shapekey = true; + bmesh_from_mesh_params.active_shapekey = ob->shapenr; + return BKE_mesh_to_bmesh_ex(me, params, &bmesh_from_mesh_params); } Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, @@ -1157,8 +1153,8 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const Mesh *me_settings) { BLI_assert(params->calc_object_remap == false); - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); - BM_mesh_bm_to_me(NULL, bm, mesh, params); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, params); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; } @@ -1167,7 +1163,7 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings) { - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; @@ -1177,8 +1173,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) { /* This is Object-level data access, * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ - if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { - Mesh *me = ob->data; + if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { + Mesh *me = (Mesh *)ob->data; float min[3], max[3]; INIT_MINMAX(min, max); @@ -1187,8 +1183,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) max[0] = max[1] = max[2] = 1.0f; } - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__); } BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; @@ -1257,13 +1253,13 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, { BKE_mesh_texspace_ensure(me); - if (r_texflag != NULL) { + if (r_texflag != nullptr) { *r_texflag = &me->texflag; } - if (r_loc != NULL) { + if (r_loc != nullptr) { *r_loc = me->loc; } - if (r_size != NULL) { + if (r_size != nullptr) { *r_size = me->size; } } @@ -1282,11 +1278,11 @@ void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) float (*BKE_mesh_orco_verts_get(Object *ob))[3] { - Mesh *me = ob->data; + Mesh *me = (Mesh *)ob->data; Mesh *tme = me->texcomesh ? me->texcomesh : me; /* Get appropriate vertex coordinates */ - float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); + float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); MVert *mvert = tme->mvert; int totvert = min_ii(tme->totvert, me->totvert); @@ -1393,28 +1389,28 @@ int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, Mesh *BKE_mesh_from_object(Object *ob) { - if (ob == NULL) { - return NULL; + if (ob == nullptr) { + return nullptr; } if (ob->type == OB_MESH) { - return ob->data; + return (Mesh *)ob->data; } - return NULL; + return nullptr; } void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) { - Mesh *old = NULL; + Mesh *old = nullptr; - if (ob == NULL) { + if (ob == nullptr) { return; } multires_force_sculpt_rebuild(ob); if (ob->type == OB_MESH) { - old = ob->data; + old = (Mesh *)ob->data; if (old) { id_us_min(&old->id); } @@ -1605,8 +1601,9 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { int i; - MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); - float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop); + MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); + float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( + &me->ldata, CD_NORMAL, me->totloop); /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ BKE_mesh_update_customdata_pointers(me, false); @@ -1616,9 +1613,8 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { mul_m4_v3(mat, fp); } @@ -1651,9 +1647,8 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { add_v3_v3(fp, offset); } @@ -1725,7 +1720,8 @@ void BKE_mesh_mselect_validate(Mesh *me) } mselect_src = me->mselect; - mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history"); + mselect_dst = (MSelect *)MEM_malloc_arrayN( + (me->totselect), sizeof(MSelect), "Mesh selection history"); for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { int index = mselect_src[i_src].index; @@ -1762,10 +1758,10 @@ void BKE_mesh_mselect_validate(Mesh *me) if (i_dst == 0) { MEM_freeN(mselect_dst); - mselect_dst = NULL; + mselect_dst = nullptr; } else if (i_dst != me->totselect) { - mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); + mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); } me->totselect = i_dst; @@ -1809,7 +1805,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) if (msel_index == -1) { /* add to the end */ - me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); + me->mselect = (MSelect *)MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); me->mselect[me->totselect].index = index; me->mselect[me->totselect].type = type; me->totselect++; @@ -1845,7 +1841,7 @@ void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] { - float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); + float(*vert_coords)[3] = (float(*)[3])MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); BKE_mesh_vert_coords_get(mesh, vert_coords); if (r_vert_len) { *r_vert_len = mesh->totvert; @@ -1856,7 +1852,8 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3(mv->co, vert_coords[i]); @@ -1869,7 +1866,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, const float mat[4][4]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { mul_v3_m4v3(mv->co, mat, vert_coords[i]); @@ -1880,7 +1878,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3_short(mv->no, vert_normals[i]); @@ -1899,35 +1898,37 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac { float(*r_loopnors)[3]; float(*polynors)[3]; - short(*clnors)[2] = NULL; + short(*clnors)[2] = nullptr; bool free_polynors = false; /* Note that we enforce computing clnors when the clnor space array is requested by caller here. - * However, we obviously only use the autosmooth angle threshold - * only in case autosmooth is enabled. */ - const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); + * However, we obviously only use the auto-smooth angle threshold + * only in case auto-smooth is enabled. */ + const bool use_split_normals = (r_lnors_spacearr != nullptr) || + ((mesh->flag & ME_AUTOSMOOTH) != 0); const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL); memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); } else { - r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + r_loopnors = (float(*)[3])CustomData_add_layer( + &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } - /* may be NULL */ - clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + /* may be nullptr */ + clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { /* This assume that layer is always up to date, not sure this is the case * (esp. in Edit mode?)... */ - polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); free_polynors = false; } else { - polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); + polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, mesh->totvert, mesh->mloop, @@ -1935,7 +1936,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac mesh->mpoly, mesh->totpoly, polynors, - NULL); + nullptr); free_polynors = true; } @@ -1953,7 +1954,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac split_angle, r_lnors_spacearr, clnors, - NULL); + nullptr); if (free_polynors) { MEM_freeN(polynors); @@ -1966,25 +1967,25 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac void BKE_mesh_calc_normals_split(Mesh *mesh) { - BKE_mesh_calc_normals_split_ex(mesh, NULL); + BKE_mesh_calc_normals_split_ex(mesh, nullptr); } /* Split faces helper functions. */ -typedef struct SplitFaceNewVert { +struct SplitFaceNewVert { struct SplitFaceNewVert *next; int new_index; int orig_index; float *vnor; -} SplitFaceNewVert; +}; -typedef struct SplitFaceNewEdge { +struct SplitFaceNewEdge { struct SplitFaceNewEdge *next; int new_index; int orig_index; int v1; int v2; -} SplitFaceNewEdge; +}; /* Detect needed new vertices, and update accordingly loops' vertex indices. * WARNING! Leaves mesh in invalid state. */ @@ -1996,7 +1997,7 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, * even when only dealing with smooth/flat faces one can find cases that no simple algorithm * can handle properly. */ - BLI_assert(lnors_spacearr != NULL); + BLI_assert(lnors_spacearr != nullptr); const int loops_len = mesh->totloop; int verts_len = mesh->totvert; @@ -2049,7 +2050,8 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, } else { /* Add new vert to list. */ - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena, + sizeof(*new_vert)); new_vert->orig_index = vert_idx; new_vert->new_index = new_vert_idx; new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ @@ -2096,7 +2098,8 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, *eval = POINTER_FROM_INT(new_edge_idx); ml_prev->e = new_edge_idx; - SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge)); + SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena, + sizeof(*new_edge)); new_edge->orig_index = edge_idx; new_edge->new_index = new_edge_idx; new_edge->v1 = ml_prev->v; @@ -2122,7 +2125,7 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, } MEM_freeN(edges_used); - BLI_edgehash_free(edges_hash, NULL); + BLI_edgehash_free(edges_hash, nullptr); return num_edges - mesh->totedge; } @@ -2181,14 +2184,14 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } BKE_mesh_tessface_clear(mesh); - MLoopNorSpaceArray lnors_spacearr = {NULL}; + MLoopNorSpaceArray lnors_spacearr = {nullptr}; /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); /* Stealing memarena from loop normals space array. */ MemArena *memarena = lnors_spacearr.mem; - SplitFaceNewVert *new_verts = NULL; - SplitFaceNewEdge *new_edges = NULL; + SplitFaceNewVert *new_verts = nullptr; + SplitFaceNewEdge *new_edges = nullptr; /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will * directly assign new indices to existing edges and loops. */ @@ -2252,10 +2255,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) /* We are here because something did change in the mesh. This means we can not trust the existing * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the * evaluated mesh and let objects to re-create it with updated settings. */ - if (mesh->runtime.mesh_eval != NULL) { - mesh->runtime.mesh_eval->edit_mesh = NULL; - BKE_id_free(NULL, mesh->runtime.mesh_eval); - mesh->runtime.mesh_eval = NULL; + if (mesh->runtime.mesh_eval != nullptr) { + mesh->runtime.mesh_eval->edit_mesh = nullptr; + BKE_id_free(nullptr, mesh->runtime.mesh_eval); + mesh->runtime.mesh_eval = nullptr; } if (DEG_is_active(depsgraph)) { Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 9f5703a015d..3447185089d 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -410,7 +410,8 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh) { const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - const BMeshCreateParams bmesh_create_params = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); BMeshFromMeshParams bmesh_from_mesh_params{}; diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index ce89c723a61..7b1d5140421 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -113,7 +113,7 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag)) /** * \brief This function clears runtime cache of the given mesh. - * + * * Call this function to recalculate runtime data when used. */ void BKE_mesh_runtime_clear_cache(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 2274d34f0f1..a046cc68bf2 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -269,7 +269,7 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_ eAttributeMapMode mode) { if (src_attribute && dst_attribute) { - this->sample_data(*src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); + this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); } } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ef84afd8668..124db07298d 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -491,11 +491,11 @@ void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER); LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { - BKE_nla_strip_foreach_id(substrip, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_nla_strip_foreach_id(substrip, data)); } } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index ab3132a5d58..e02ea3f7e37 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -66,6 +66,7 @@ #include "BKE_colortools.h" #include "BKE_cryptomatte.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" @@ -129,10 +130,6 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree, struct bNode *node, const bool mute); -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface); -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface); static void ntree_init_data(ID *id) { @@ -245,9 +242,16 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c ntree_dst->interface_type = nullptr; if (ntree_src->field_inferencing_interface) { - ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy( + ntree_dst->field_inferencing_interface = new FieldInferencingInterface( *ntree_src->field_inferencing_interface); } + + if (flag & LIB_ID_COPY_NO_PREVIEW) { + ntree_dst->preview = nullptr; + } + else { + BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id); + } } static void ntree_free_data(ID *id) @@ -293,7 +297,7 @@ static void ntree_free_data(ID *id) MEM_freeN(sock); } - node_field_inferencing_interface_free(ntree->field_inferencing_interface); + delete ntree->field_inferencing_interface; /* free preview hash */ if (ntree->previews) { @@ -303,12 +307,16 @@ static void ntree_free_data(ID *id) if (ntree->id.tag & LIB_TAG_LOCALIZED) { BKE_libblock_free_data(&ntree->id, true); } + + BKE_previewimg_free(&ntree->preview); } static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { @@ -360,21 +368,25 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER); - IDP_foreach_property( - node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(node->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } @@ -635,6 +647,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { write_node_socket_interface(writer, sock); } + + BKE_previewimg_blend_write(writer, ntree->preview); } static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -665,6 +679,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) BLO_read_data_address(reader, &sock->default_value); sock->total_inputs = 0; /* Clear runtime data set before drawing. */ sock->cache = nullptr; + sock->declaration = nullptr; } /* ntree itself has been read! */ @@ -828,6 +843,9 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->update |= NTREE_UPDATE_FIELD_INFERENCING; } + BLO_read_data_address(reader, &ntree->preview); + BKE_previewimg_blend_read(reader, ntree->preview); + /* type verification is in lib-link */ } @@ -1051,8 +1069,7 @@ IDTypeInfo IDType_ID_NT = { static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { if (ntype->declare != nullptr) { - nodeDeclarationEnsure(ntree, node); - node->declaration->build(*ntree, *node); + node_verify_sockets(ntree, node, true); return; } bNodeSocketTemplate *sockdef; @@ -1141,15 +1158,15 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) { if (typeinfo) { ntree->typeinfo = typeinfo; - - /* deprecated integer type */ - ntree->type = typeinfo->type; } else { ntree->typeinfo = &NodeTreeTypeUndefined; ntree->init &= ~NTREE_TYPE_INIT; } + + /* Deprecated integer type. */ + ntree->type = ntree->typeinfo->type; } static void node_set_typeinfo(const struct bContext *C, @@ -1523,7 +1540,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree, } /* make the identifier unique */ BLI_uniquename_cb( - unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); + unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); sock->in_out = in_out; @@ -3975,8 +3992,10 @@ int nodeSocketIsHidden(const bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } -void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) +void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available) { + /* #ntree is not needed right now, but it's generally necessary when changing the tree because we + * want to tag it as changed in the future. */ if (is_available) { sock->flag &= ~SOCK_UNAVAIL; } @@ -3999,17 +4018,38 @@ int nodeSocketLinkLimit(const bNodeSocket *sock) return sock->limit; } +static void update_socket_declarations(ListBase *sockets, + Span<blender::nodes::SocketDeclarationPtr> declarations) +{ + int index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { + const SocketDeclaration &socket_decl = *declarations[index]; + socket->declaration = &socket_decl; + } +} + /** - * If the node implements a `declare` function, this function makes sure that `node->declaration` - * is up to date. + * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration + * and sockets are up to date already. */ -void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) +void nodeSocketDeclarationsUpdate(bNode *node) +{ + BLI_assert(node->declaration != nullptr); + update_socket_declarations(&node->inputs, node->declaration->inputs()); + update_socket_declarations(&node->outputs, node->declaration->outputs()); +} + +/** + * Just update `node->declaration` if necessary. This can also be called on nodes that may not be + * up to date (e.g. because the need versioning or are dynamic). + */ +bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) { if (node->declaration != nullptr) { - return; + return false; } if (node->typeinfo->declare == nullptr) { - return; + return false; } if (node->typeinfo->declaration_is_dynamic) { node->declaration = new blender::nodes::NodeDeclaration(); @@ -4021,6 +4061,20 @@ void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) BLI_assert(node->typeinfo->fixed_declaration != nullptr); node->declaration = node->typeinfo->fixed_declaration; } + return true; +} + +/** + * If the node implements a `declare` function, this function makes sure that `node->declaration` + * is up to date. It is expected that the sockets of the node are up to date already. + */ +bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node) +{ + if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) { + nodeSocketDeclarationsUpdate(node); + return true; + } + return false; } /* ************** Node Clipboard *********** */ @@ -4492,18 +4546,6 @@ void ntreeUpdateAllNew(Main *main) FOREACH_NODETREE_END; } -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface) -{ - return new FieldInferencingInterface(field_inferencing_interface); -} - -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface) -{ - delete field_inferencing_interface; -} - namespace blender::bke::node_field_inferencing { static bool is_field_socket_type(eNodeSocketDatatype type) @@ -5195,9 +5237,8 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id) void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) { BLI_freelistN(&node->internal_links); - - if (node->typeinfo && node->typeinfo->update_internal_links) { - node->typeinfo->update_internal_links(ntree, node); + if (!node->typeinfo->no_muting) { + node_internal_links_create(ntree, node); } } @@ -5462,12 +5503,6 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) ntype->gpu_fn = gpu_fn; } -void node_type_internal_links(bNodeType *ntype, - void (*update_internal_links)(bNodeTree *, bNode *)) -{ - ntype->update_internal_links = update_internal_links; -} - /* callbacks for undefined types */ static bool node_undefined_poll(bNodeType *UNUSED(ntype), @@ -5485,6 +5520,7 @@ static void register_undefined_types() * they are just used as placeholders in case the actual types are not registered. */ + NodeTreeTypeUndefined.type = NTREE_UNDEFINED; strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 4b01ee29828..b2dd4b40bae 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -160,11 +160,10 @@ static CLG_LogRef LOG = {"bke.object"}; /** - * Vertex parent modifies original BMesh which is not safe for threading. + * NOTE(@sergey): Vertex parent modifies original #BMesh which is not safe for threading. * Ideally such a modification should be handled as a separate DAG update - * callback for mesh datablock, but for until it is actually supported use + * callback for mesh data-block, but for until it is actually supported use * simpler solution with a mutex lock. - * - sergey - */ #define VPARENT_THREADING_HACK @@ -390,7 +389,8 @@ static void library_foreach_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, @@ -399,7 +399,8 @@ static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_shaderfxForeachIDLink(void *user_data, @@ -408,7 +409,8 @@ static void library_foreach_shaderfxForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), @@ -418,7 +420,8 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), @@ -427,7 +430,8 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void object_foreach_id(ID *id, LibraryForeachIDData *data) @@ -494,10 +498,18 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( data, proxy_cb_flag, false); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - IDP_foreach_property( - pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(pchan->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER); - BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop( + &pchan->constraints, library_foreach_constraintObjectLooper, data)); } BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); } @@ -509,14 +521,21 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); } - BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data); - BKE_gpencil_modifiers_foreach_ID_link( - object, library_foreach_gpencil_modifiersForeachIDLink, data); - BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data); - BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_gpencil_modifiers_foreach_ID_link( + object, library_foreach_gpencil_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data)); LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data)); } if (object->soft) { @@ -1204,7 +1223,7 @@ static IDProperty *object_asset_dimensions_property(Object *ob) return nullptr; } - IDPropertyTemplate idprop = {0}; + IDPropertyTemplate idprop{}; idprop.array.len = ARRAY_SIZE(dimensions); idprop.array.type = IDP_FLOAT; @@ -1747,24 +1766,24 @@ static void object_update_from_subsurf_ccg(Object *object) /* NOTE: we need to reshape into an original mesh from main database, * allowing: * - * - Update copies of that mesh at any moment. - * - Save the file without doing extra reshape. - * - All the users of the mesh have updated displacement. + * - Update copies of that mesh at any moment. + * - Save the file without doing extra reshape. + * - All the users of the mesh have updated displacement. * * However, the tricky part here is that we only know about sculpted * state of a mesh on an object level, and object is being updated after - * mesh datablock is updated. This forces us to: + * mesh data-block is updated. This forces us to: * - * - Update mesh datablock from object evaluation, which is technically - * forbidden, but there is no other place for this yet. - * - Reshape to the original mesh from main database, and then copy updated - * layer to copy of that mesh (since copy of the mesh has decoupled - * custom data layers). + * - Update mesh data-block from object evaluation, which is technically + * forbidden, but there is no other place for this yet. + * - Reshape to the original mesh from main database, and then copy updated + * layer to copy of that mesh (since copy of the mesh has decoupled + * custom data layers). * * All this is defeating all the designs we need to follow to allow safe * threaded evaluation, but this is as good as we can make it within the * current sculpt/evaluated mesh design. This is also how we've survived - * with old DerivedMesh based solutions. So, while this is all wrong and + * with old #DerivedMesh based solutions. So, while this is all wrong and * needs reconsideration, doesn't seem to be a big stopper for real * production artists. */ @@ -1803,7 +1822,7 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own object_eval->runtime.data_eval = data_eval; object_eval->runtime.is_data_eval_owned = is_owned; - /* Overwrite data of evaluated object, if the datablock types match. */ + /* Overwrite data of evaluated object, if the data-block types match. */ ID *data = (ID *)object_eval->data; if (GS(data->name) == GS(data_eval->name)) { /* NOTE: we are not supposed to invoke evaluation for original objects, @@ -1845,8 +1864,8 @@ void BKE_object_free_derived_caches(Object *ob) ob->runtime.mesh_deform_eval = nullptr; } - /* Restore initial pointer for copy-on-write datablocks, object->data - * might be pointing to an evaluated datablock data was just freed above. */ + /* Restore initial pointer for copy-on-write data-blocks, object->data + * might be pointing to an evaluated data-block data was just freed above. */ if (ob->runtime.data_orig != nullptr) { ob->data = ob->runtime.data_orig; } @@ -2345,13 +2364,13 @@ Object *BKE_object_add_from( } /** - * Add a new object, but assign the given datablock as the ob->data + * Add a new object, but assign the given data-block as the `ob->data` * for the newly created object. * - * \param data: The datablock to assign as ob->data for the new object. - * This is assumed to be of the correct type. - * \param do_id_user: If true, id_us_plus() will be called on data when - * assigning it to the object. + * \param data: The data-block to assign as `ob->data` for the new object. + * This is assumed to be of the correct type. + * \param do_id_user: If true, #id_us_plus() will be called on data when + * assigning it to the object. */ Object *BKE_object_add_for_data( Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user) @@ -2616,7 +2635,7 @@ Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, Object *ob_pose = BKE_object_pose_armature_get(ob_active); Object **objects = nullptr; if (ob_pose == ob_active) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2663,7 +2682,7 @@ Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, } if (base_active && (base_pose == base_active)) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2851,7 +2870,7 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid((ID *)&obn->id); + BKE_libblock_relink_to_newid(bmain, &obn->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ @@ -4285,7 +4304,7 @@ void BKE_object_foreach_display_point(Object *ob, } } else if (ob->type == OB_GPENCIL) { - GPencilStrokePointIterData iter_data = {nullptr}; + GPencilStrokePointIterData iter_data{}; iter_data.obmat = obmat; iter_data.point_func_cb = func_cb; iter_data.user_data = user_data; @@ -4323,28 +4342,18 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph, } /** - * Struct members from DNA_object_types.h + * See struct members from #Object in DNA_object_types.h */ struct ObTfmBack { float loc[3], dloc[3]; - /** scale and delta scale. */ float scale[3], dscale[3]; - /** euler rotation. */ float rot[3], drot[3]; - /** quaternion rotation. */ float quat[4], dquat[4]; - /** axis angle rotation - axis part. */ float rotAxis[3], drotAxis[3]; - /** axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** final worldspace matrix with constraints & animsys applied. */ float obmat[4][4]; - /** inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; - /** inverse result of constraints. doesn't include effect of parent or object local transform. - */ float constinv[4][4]; - /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */ float imat[4][4]; }; @@ -5401,7 +5410,7 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob) } /** - * Return a KDTree_3d from the deformed object (in worldspace) + * Return a KDTree_3d from the deformed object (in world-space). * * \note Only mesh objects currently support deforming, others are TODO. * @@ -5427,7 +5436,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) MVert *mvert = me_eval->mvert; uint totvert = me_eval->totvert; - /* tree over-allocs in case where some verts have ORIGINDEX_NONE */ + /* Tree over-allocates in case where some verts have #ORIGINDEX_NONE. */ tot = 0; tree = BLI_kdtree_3d_new(totvert); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b13fd8a395f..b158633294e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -180,7 +180,8 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (psett->mtex[i]) { - BKE_texture_mtex_foreach_id(data, psett->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, psett->mtex[i])); } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 3358f3e6dea..2318a05e635 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -2798,7 +2798,7 @@ float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3] void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int totvert) { if (totvert != pbvh->totvert) { - BLI_assert_msg(0, "PBVH: Given deforming vcos number does not natch PBVH vertex number!"); + BLI_assert_msg(0, "PBVH: Given deforming vcos number does not match PBVH vertex number!"); return; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 0aeee11ed17..a0bd3abbc1a 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -471,7 +471,8 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } /** @@ -522,7 +523,10 @@ static void scene_foreach_toolsettings_id_pointer_process( } } -#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS( \ +/* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency + * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData + * *data` is NULL. */ +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \ __data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \ { \ if (__do_undo_restore) { \ @@ -530,24 +534,38 @@ static void scene_foreach_toolsettings_id_pointer_process( (ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \ } \ else { \ + BLI_assert((__data) != NULL); \ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \ } \ } \ (void)0 +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( \ + __data, __do_undo_restore, __func_call) \ + { \ + if (__do_undo_restore) { \ + __func_call; \ + } \ + else { \ + BLI_assert((__data) != NULL); \ + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \ + } \ + } \ + (void)0 + static void scene_foreach_paint(LibraryForeachIDData *data, Paint *paint, const bool do_undo_restore, BlendLibReader *reader, Paint *paint_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->brush, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->brush, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); for (int i = 0; i < paint_old->tool_slots_len; i++) { /* This is a bit tricky. * - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so @@ -559,21 +577,21 @@ static void scene_foreach_paint(LibraryForeachIDData *data, */ Brush *brush_tmp = NULL; Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp; - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - *brush_p, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); - } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->palette, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->palette, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + *brush_p, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->palette, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->palette, + IDWALK_CB_USER); } static void scene_foreach_toolsettings(LibraryForeachIDData *data, @@ -582,110 +600,152 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data, BlendLibReader *reader, ToolSettings *toolsett_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.scene, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.scene, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.object, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.shape_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.shape_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.scene, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.scene, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.object, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.shape_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.shape_object, + IDWALK_CB_NOP); scene_foreach_paint( data, &toolsett->imapaint.paint, do_undo_restore, reader, &toolsett_old->imapaint.paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.stencil, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.stencil, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.clone, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.clone, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.canvas, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.canvas, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.stencil, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.stencil, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.clone, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.clone, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.canvas, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.canvas, + IDWALK_CB_USER); if (toolsett->vpaint) { - scene_foreach_paint( - data, &toolsett->vpaint->paint, do_undo_restore, reader, &toolsett_old->vpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->vpaint->paint, + do_undo_restore, + reader, + &toolsett_old->vpaint->paint)); } if (toolsett->wpaint) { - scene_foreach_paint( - data, &toolsett->wpaint->paint, do_undo_restore, reader, &toolsett_old->wpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->wpaint->paint, + do_undo_restore, + reader, + &toolsett_old->wpaint->paint)); } if (toolsett->sculpt) { - scene_foreach_paint( - data, &toolsett->sculpt->paint, do_undo_restore, reader, &toolsett_old->sculpt->paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->sculpt->gravity_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->sculpt->gravity_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->sculpt->paint, + do_undo_restore, + reader, + &toolsett_old->sculpt->paint)); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->sculpt->gravity_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->sculpt->gravity_object, + IDWALK_CB_NOP); } if (toolsett->uvsculpt) { - scene_foreach_paint( - data, &toolsett->uvsculpt->paint, do_undo_restore, reader, &toolsett_old->uvsculpt->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->uvsculpt->paint, + do_undo_restore, + reader, + &toolsett_old->uvsculpt->paint)); } if (toolsett->gp_paint) { - scene_foreach_paint( - data, &toolsett->gp_paint->paint, do_undo_restore, reader, &toolsett_old->gp_paint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_paint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_paint->paint)); } if (toolsett->gp_vertexpaint) { - scene_foreach_paint(data, - &toolsett->gp_vertexpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_vertexpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_vertexpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_vertexpaint->paint)); } if (toolsett->gp_sculptpaint) { - scene_foreach_paint(data, - &toolsett->gp_sculptpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_sculptpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_sculptpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_sculptpaint->paint)); } if (toolsett->gp_weightpaint) { - scene_foreach_paint(data, - &toolsett->gp_weightpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_weightpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_weightpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_weightpaint->paint)); } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->gp_sculpt.guide.reference_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->gp_sculpt.guide.reference_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->gp_sculpt.guide.reference_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->gp_sculpt.guide.reference_object, + IDWALK_CB_NOP); } +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL + static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) { LISTBASE_FOREACH (LayerCollection *, lc, lb) { @@ -707,7 +767,8 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data) #define FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \ { \ CHECK_TYPE(&((_id_super)->id), ID *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return false; \ } \ } \ @@ -746,15 +807,18 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->r.bake.cage_object, IDWALK_CB_NOP); if (scene->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree)); } if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data)); } /* This pointer can be NULL during old files reading, better be safe than sorry. */ if (scene->master_collection != NULL) { - BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection)); } LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { @@ -765,7 +829,8 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE); } - scene_foreach_layer_collection(data, &view_layer->layer_collections); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_layer_collection(data, &view_layer->layer_collections)); LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { if (fmc->script) { @@ -786,18 +851,25 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP); - IDP_foreach_property( - marker->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(marker->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } ToolSettings *toolsett = scene->toolsettings; if (toolsett) { - scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett)); } if (scene->rigidbody_world) { - BKE_rigidbody_world_id_loop( - scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_rigidbody_world_id_loop( + scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data)); } } @@ -1853,7 +1925,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&sce_copy->id); + BKE_libblock_relink_to_newid(bmain, &sce_copy->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 233a4f344b5..6352e08ec4b 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -97,6 +97,10 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet * } } +/** + * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). + */ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP); @@ -107,10 +111,8 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area switch (sl->spacetype) { case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP); - if (v3d->localvd) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP); } @@ -118,13 +120,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_GRAPH: { SpaceGraph *sipo = (SpaceGraph *)sl; - - screen_foreach_id_dopesheet(data, sipo->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, sipo->ads)); break; } case SPACE_PROPERTIES: { SpaceProperties *sbuts = (SpaceProperties *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP); break; } @@ -132,14 +133,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area break; case SPACE_ACTION: { SpaceAction *saction = (SpaceAction *)sl; - screen_foreach_id_dopesheet(data, &saction->ads); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, saction->action, IDWALK_CB_NOP); break; } case SPACE_IMAGE: { SpaceImage *sima = (SpaceImage *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->image, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->gpd, IDWALK_CB_USER); @@ -147,33 +146,28 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_SEQ: { SpaceSeq *sseq = (SpaceSeq *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER); break; } case SPACE_NLA: { SpaceNla *snla = (SpaceNla *)sl; - - screen_foreach_id_dopesheet(data, snla->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, snla->ads)); break; } case SPACE_TEXT: { SpaceText *st = (SpaceText *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP); break; } case SPACE_SCRIPT: { SpaceScript *scpt = (SpaceScript *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP); break; } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP); - if (space_outliner->treestore != NULL) { TreeStoreElem *tselem; BLI_mempool_iter iter; @@ -187,13 +181,11 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_NODE: { SpaceNode *snode = (SpaceNode *)sl; - const bool is_private_nodetree = snode->id != NULL && ntreeFromID(snode->id) == snode->nodetree; BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP); - BKE_LIB_FOREACHID_PROCESS_IDSUPER( data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); @@ -219,14 +211,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_CLIP: { SpaceClip *sclip = (SpaceClip *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); break; } case SPACE_SPREADSHEET: { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { if (context->type == SPREADSHEET_CONTEXT_OBJECT) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( @@ -243,12 +233,13 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area static void screen_foreach_id(ID *id, LibraryForeachIDData *data) { - if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { - bScreen *screen = (bScreen *)id; + if ((BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) == 0) { + return; + } + bScreen *screen = (bScreen *)id; - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - BKE_screen_foreach_id_screen_area(data, area); - } + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_screen_foreach_id_screen_area(data, area)); } } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 1d297b3ced9..98e7405bde6 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -103,7 +103,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) Simulation *simulation = (Simulation *)id; if (simulation->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree)); } } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index b7eb9d31b23..a008edd038a 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2633,7 +2633,7 @@ static void interpolate_exciter(Object *ob, int timescale, int time) } } -/* ************ convertors ********** */ +/* ************ converters ********** */ /* for each object type we need; * - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index c2c9d178171..52bbd2bec57 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -30,14 +30,12 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::attribute_math::convert_to_static_type; using blender::bke::AttributeIDRef; using blender::fn::GMutableSpan; using blender::fn::GSpan; using blender::fn::GVArray; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; Spline::Type Spline::type() const { @@ -416,7 +414,7 @@ Span<float3> Spline::evaluated_normals() const } /* Rotate the generated normals with the interpolated tilt data. */ - GVArray_Typed<float> tilts = this->interpolate_to_evaluated(this->tilts()); + VArray<float> tilts = this->interpolate_to_evaluated(this->tilts()); for (const int i : normals.index_range()) { normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]); } @@ -529,9 +527,9 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) } } -GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const +GVArray Spline::interpolate_to_evaluated(GSpan data) const { - return this->interpolate_to_evaluated(GVArray_For_GSpan(data)); + return this->interpolate_to_evaluated(GVArray::ForSpan(data)); } /** @@ -547,7 +545,7 @@ void Spline::sample_with_index_factors(const GVArray &src, blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - const GVArray_Typed<T> src_typed = src.typed<T>(); + const VArray<T> src_typed = src.typed<T>(); MutableSpan<T> dst_typed = dst.typed<T>(); if (src.size() == 1) { dst_typed.fill(src_typed[0]); diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 18d195f19da..0cadab998f5 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -25,9 +25,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArrayPtr; void BezierSpline::copy_settings(Spline &dst) const { @@ -708,26 +707,26 @@ static void interpolate_to_evaluated_impl(const BezierSpline &spline, } } -GVArrayPtr BezierSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } const int eval_size = this->evaluated_points_size(); if (eval_size == 1) { - return src.shallow_copy(); + return src; } - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(eval_size); interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 6d30d8ba916..7fa332a0330 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -26,10 +26,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; void NURBSpline::copy_settings(Spline &dst) const { @@ -410,23 +408,23 @@ void interpolate_to_evaluated_impl(Span<NURBSpline::BasisCache> weights, mixer.finalize(); } -GVArrayPtr NURBSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } Span<BasisCache> basis_cache = this->calculate_basis_cache(); - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(this->evaluated_points_size()); interpolate_to_evaluated_impl<T>(basis_cache, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); @@ -448,8 +446,8 @@ Span<float3> NURBSpline::evaluated_positions() const evaluated_position_cache_.resize(eval_size); /* TODO: Avoid copying the evaluated data from the temporary array. */ - GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); - evaluated->materialize(evaluated_position_cache_); + VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); + evaluated.materialize(evaluated_position_cache_); position_cache_dirty_ = false; return evaluated_position_cache_; diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc index 338b5d0ac9e..d495c977285 100644 --- a/source/blender/blenkernel/intern/spline_poly.cc +++ b/source/blender/blenkernel/intern/spline_poly.cc @@ -23,7 +23,6 @@ using blender::float3; using blender::MutableSpan; using blender::Span; using blender::fn::GVArray; -using blender::fn::GVArrayPtr; void PolySpline::copy_settings(Spline &UNUSED(dst)) const { @@ -122,9 +121,8 @@ Span<float3> PolySpline::evaluated_positions() const * the original data. Therefore the lifetime of the returned virtual array must not be longer than * the source data. */ -GVArrayPtr PolySpline::interpolate_to_evaluated(const GVArray &src) const +GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); - - return src.shallow_copy(); + return src; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0c58c8e8a5a..6796b1ac397 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2020,7 +2020,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; - /* Copy over poly data, e.g. mtexpoly. */ + /* Copy over poly data, e.g. #CD_FACEMAP. */ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); /* Set original index data. */ diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 0cb2218e7e0..7ac9e20d1a7 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1977,7 +1977,7 @@ static char tab_to_spaces[] = " "; static void txt_convert_tab_to_spaces(Text *text) { /* sb aims to pad adjust the tab-width needed so that the right number of spaces - * is added so that the indention of the line is the right width (i.e. aligned + * is added so that the indentation of the line is the right width (i.e. aligned * to multiples of TXT_TABSIZE) */ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c878abf0dff..a8c8eaa6a1c 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -142,7 +142,8 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data) Tex *texture = (Tex *)id; if (texture->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, texture->ima, IDWALK_CB_USER); } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index fe03c5b817a..2f0a282a298 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -131,7 +131,8 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data) if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree)); } } diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh new file mode 100644 index 00000000000..0fc5de5540f --- /dev/null +++ b/source/blender/blenlib/BLI_any.hh @@ -0,0 +1,319 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bli + * + * A #blender::Any is a type-safe container for single values of any copy constructible type. + * It is similar to #std::any but provides the following two additional features: + * - Adjustable inline buffer capacity and alignment. #std::any has a small inline buffer in most + * implementations as well, but its size is not guaranteed. + * - Can store additional user-defined type information without increasing the stack size of #Any. + */ + +#include <algorithm> +#include <utility> + +#include "BLI_memory_utils.hh" + +namespace blender { + +namespace detail { + +/** + * Contains function pointers that manage the memory in an #Any. + * Additional type specific #ExtraInfo can be embedded here as well. + */ +template<typename ExtraInfo> struct AnyTypeInfo { + void (*copy_construct)(void *dst, const void *src); + void (*move_construct)(void *dst, void *src); + void (*destruct)(void *src); + const void *(*get)(const void *src); + ExtraInfo extra_info; + + /** + * Used when #T is stored directly in the inline buffer of the #Any. + */ + template<typename T> static const AnyTypeInfo &get_for_inline() + { + static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); }, + [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); }, + [](void *src) { ((T *)src)->~T(); }, + [](const void *src) { return src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr + * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer. + */ + template<typename T> static const AnyTypeInfo &get_for_unique_ptr() + { + using Ptr = std::unique_ptr<T>; + static AnyTypeInfo funcs = { + [](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); }, + [](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); }, + [](void *src) { ((Ptr *)src)->~Ptr(); }, + [](const void *src) -> const void * { return &**(const Ptr *)src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when the #Any does not contain any type currently. + */ + static const AnyTypeInfo &get_for_empty() + { + static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {}, + [](void *UNUSED(dst), void *UNUSED(src)) {}, + [](void *UNUSED(src)) {}, + [](const void *UNUSED(src)) -> const void * { return nullptr; }, + ExtraInfo{}}; + return funcs; + } +}; + +/** + * Dummy extra info that is used when no additional type information should be stored in the #Any. + */ +struct NoExtraInfo { + template<typename T> static NoExtraInfo get() + { + return {}; + } +}; + +} // namespace detail + +template< + /** + * Either void or a struct that contains data members for additional type information. + * The struct has to have a static `ExtraInfo get<T>()` method that initializes the struct + * based on a type. + */ + typename ExtraInfo = void, + /** + * Size of the inline buffer. This allows types that are small enough to be stored directly + * inside the #Any without an additional allocation. + */ + size_t InlineBufferCapacity = 8, + /** + * Required minimum alignment of the inline buffer. If this is smaller than the alignment + * requirement of a used type, a separate allocation is necessary. + */ + size_t Alignment = 8> +class Any { + private: + /* Makes it possible to use void in the template parameters. */ + using RealExtraInfo = + std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>; + using Info = detail::AnyTypeInfo<RealExtraInfo>; + + /** + * Inline buffer that either contains nothing, the stored value directly, or a #std::unique_ptr + * to the value. + */ + AlignedBuffer<std::max(InlineBufferCapacity, sizeof(std::unique_ptr<int>)), Alignment> buffer_{}; + + /** + * Information about the type that is currently stored. + */ + const Info *info_ = &Info::get_for_empty(); + + public: + /** Only copy constructible types can be stored in #Any. */ + template<typename T> static constexpr inline bool is_allowed_v = std::is_copy_constructible_v<T>; + + /** + * Checks if the type will be stored in the inline buffer or if it requires a separate + * allocation. + */ + template<typename T> + static constexpr inline bool is_inline_v = std::is_nothrow_move_constructible_v<T> && + sizeof(T) <= InlineBufferCapacity && + alignof(T) <= Alignment; + + /** + * Checks if #T is the same type as this #Any, because in this case the behavior of e.g. the + * assignment operator is different. + */ + template<typename T> + static constexpr inline bool is_same_any_v = std::is_same_v<std::decay_t<T>, Any>; + + private: + template<typename T> const Info &get_info() const + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + if constexpr (is_inline_v<DecayT>) { + return Info::template get_for_inline<DecayT>(); + } + else { + return Info::template get_for_unique_ptr<DecayT>(); + } + } + + public: + Any() = default; + + Any(const Any &other) : info_(other.info_) + { + info_->copy_construct(&buffer_, &other.buffer_); + } + + /** + * \note The #other #Any will not be empty afterwards if it was not before. Just its value is in + * a moved-from state. + */ + Any(Any &&other) noexcept : info_(other.info_) + { + info_->move_construct(&buffer_, &other.buffer_); + } + + /** + * Constructs a new #Any that contains the given type #T from #args. The #std::in_place_type_t is + * used to disambiguate this and the copy/move constructors. + */ + template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args) + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + info_ = &this->template get_info<DecayT>(); + if constexpr (is_inline_v<DecayT>) { + /* Construct the value directly in the inline buffer. */ + new (&buffer_) DecayT(std::forward<Args>(args)...); + } + else { + /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline + * buffer. */ + new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...)); + } + } + + /** + * Constructs a new #Any that contains the given value. + */ + template<typename T, typename X = std::enable_if_t<!is_same_any_v<T>, void>> + Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value)) + { + } + + ~Any() + { + info_->destruct(&buffer_); + } + + /** + * \note: Only needed because the template below does not count as copy assignment operator. + */ + Any &operator=(const Any &other) + { + if (this == &other) { + return *this; + } + this->~Any(); + new (this) Any(other); + return *this; + } + + /** Assign any value to the #Any. */ + template<typename T> Any &operator=(T &&other) + { + if constexpr (is_same_any_v<T>) { + if (this == &other) { + return *this; + } + } + this->~Any(); + new (this) Any(std::forward<T>(other)); + return *this; + } + + /** Destruct any existing value to make it empty. */ + void reset() + { + info_->destruct(&buffer_); + info_ = &Info::get_for_empty(); + } + + operator bool() const + { + return this->has_value(); + } + + bool has_value() const + { + return info_ != &Info::get_for_empty(); + } + + template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args) + { + this->~Any(); + new (this) Any(std::in_place_type<T>, std::forward<Args>(args)...); + return this->get<T>(); + } + + /** Return true when the value that is currently stored is a #T. */ + template<typename T> bool is() const + { + return info_ == &this->template get_info<T>(); + } + + /** Get a pointer to the stored value. */ + void *get() + { + return const_cast<void *>(info_->get(&buffer_)); + } + + /** Get a pointer to the stored value. */ + const void *get() const + { + return info_->get(&buffer_); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> std::decay_t<T> &get() + { + BLI_assert(this->is<T>()); + return *static_cast<std::decay_t<T> *>(this->get()); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> const std::decay_t<T> &get() const + { + BLI_assert(this->is<T>()); + return *static_cast<const std::decay_t<T> *>(this->get()); + } + + /** + * Get extra information that has been stored for the contained type. + */ + const RealExtraInfo &extra_info() const + { + return info_->extra_info; + } +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index fb52436587f..ca06a3e3545 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -110,8 +110,8 @@ bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const flo bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius); bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b); bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b); -void BLI_rcti_union(struct rcti *rct1, const struct rcti *rct2); -void BLI_rctf_union(struct rctf *rct1, const struct rctf *rct2); +void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b); +void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b); void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src); void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src); void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src); diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh index 7b8aa03b807..051731ab801 100644 --- a/source/blender/blenlib/BLI_serialize.hh +++ b/source/blender/blenlib/BLI_serialize.hh @@ -103,11 +103,11 @@ using IntValue = PrimitiveValue<int64_t, eValueType::Int>; using DoubleValue = PrimitiveValue<double, eValueType::Double>; using BooleanValue = PrimitiveValue<bool, eValueType::Boolean>; -template<typename Container, typename ContainerItem, eValueType V> class ContainerValue; +template<typename Container, eValueType V, typename ContainerItem = typename Container::value_type> +class ContainerValue; /* ArrayValue stores its items as shared pointer as it shares data with a lookup table that can * be created by calling `create_lookup`. */ -using ArrayValue = - ContainerValue<Vector<std::shared_ptr<Value>>, std::shared_ptr<Value>, eValueType::Array>; +using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array>; /** * Class containing a (de)serializable value. @@ -138,7 +138,7 @@ class Value { public: virtual ~Value() = default; - const eValueType type() const + eValueType type() const { return type_; } @@ -234,11 +234,11 @@ template< /** The container type where the elements are stored in. */ typename Container, - /** Type of the data inside the container. */ - typename ContainerItem, - /** ValueType representing the value (object/array). */ - eValueType V> + eValueType V, + + /** Type of the data inside the container. */ + typename ContainerItem> class ContainerValue : public Value { public: using Items = Container; @@ -275,8 +275,7 @@ using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>; * Object is a key-value container where the key must be a std::string. * Internally it is stored in a blender::Vector to ensure the order of keys. */ -class ObjectValue - : public ContainerValue<Vector<ObjectElementType>, ObjectElementType, eValueType::Object> { +class ObjectValue : public ContainerValue<Vector<ObjectElementType>, eValueType::Object> { public: using LookupValue = std::shared_ptr<Value>; using Lookup = Map<std::string, LookupValue>; diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 1c02bce8411..d9f83d3e1cb 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -37,148 +37,98 @@ * see of the increased compile time and binary size is worth it. */ +#include "BLI_any.hh" #include "BLI_array.hh" #include "BLI_index_mask.hh" #include "BLI_span.hh" namespace blender { -/* An immutable virtual array. */ -template<typename T> class VArray { +/* Forward declarations for generic virtual arrays. */ +namespace fn { +class GVArray; +class GVMutableArray; +}; // namespace fn + +/** + * Implements the specifics of how the elements of a virtual array are accessed. It contains a + * bunch of virtual methods that are wrapped by #VArray. + */ +template<typename T> class VArrayImpl { protected: + /** + * Number of elements in the virtual array. All virtual arrays have a size, but in some cases it + * may make sense to set it to the max value. + */ int64_t size_; public: - VArray(const int64_t size) : size_(size) + VArrayImpl(const int64_t size) : size_(size) { BLI_assert(size_ >= 0); } - virtual ~VArray() = default; - - T get(const int64_t index) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - return this->get_impl(index); - } + virtual ~VArrayImpl() = default; int64_t size() const { return size_; } - bool is_empty() const - { - return size_ == 0; - } - - IndexRange index_range() const - { - return IndexRange(size_); - } - - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } - - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - Span<T> get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return {}; - } - return this->get_internal_span_impl(); - } + /** + * Get the element at #index. This does not return a reference, because the value may be computed + * on the fly. + */ + virtual T get(const int64_t index) const = 0; - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } - - /* Returns the value that is returned for every index. This invokes undefined behavior if the - * virtual array would not return the same value for every index. */ - T get_internal_single() const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - return this->get(0); - } - return this->get_internal_single_impl(); - } - - /* Get the element at a specific index. Note that this operator cannot be used to assign values - * to an index, because the return value is not a reference. */ - T operator[](const int64_t index) const - { - return this->get(index); - } - - /* Copy the entire virtual array into a span. */ - void materialize(MutableSpan<T> r_span) const - { - this->materialize(IndexMask(size_), r_span); - } - - /* Copy some indices of the virtual array into a span. */ - void materialize(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_impl(mask, r_span); - } - - void materialize_to_uninitialized(MutableSpan<T> r_span) const - { - this->materialize_to_uninitialized(IndexMask(size_), r_span); - } - - void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, r_span); - } - - protected: - virtual T get_impl(const int64_t index) const = 0; - - virtual bool is_span_impl() const + /** + * Return true when the virtual array is a plain array internally. + */ + virtual bool is_span() const { return false; } - virtual Span<T> get_internal_span_impl() const + /** + * Return the span of the virtual array. + * This invokes undefined behavior when #is_span returned false. + */ + virtual Span<T> get_internal_span() const { + /* Provide a default implementation, so that subclasses don't have to provide it. This method + * should never be called because #is_span returns false by default. */ BLI_assert_unreachable(); return {}; } - virtual bool is_single_impl() const + /** + * Return true when the virtual array has the same value at every index. + */ + virtual bool is_single() const { return false; } - virtual T get_internal_single_impl() const + /** + * Return the value that is used at every index. + * This invokes undefined behavior when #is_single returned false. + */ + virtual T get_internal_single() const { /* Provide a default implementation, so that subclasses don't have to provide it. This method - * should never be called because `is_single_impl` returns false by default. */ + * should never be called because #is_single returns false by default. */ BLI_assert_unreachable(); return T(); } - virtual void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Copy values from the virtual array into the provided span. The index of the value in the + * virtual is the same as the index in the span. + */ + virtual void materialize(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { dst[i] = src[i]; }); @@ -192,9 +142,13 @@ template<typename T> class VArray { } } - virtual void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Same as #materialize but #r_span is expected to be uninitialized. + */ + virtual void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { new (dst + i) T(src[i]); }); @@ -207,43 +161,48 @@ template<typename T> class VArray { mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); }); } } -}; -/* Similar to VArray, but the elements are mutable. */ -template<typename T> class VMutableArray : public VArray<T> { - public: - VMutableArray(const int64_t size) : VArray<T>(size) + /** + * If this virtual wraps another #GVArray, this method should assign the wrapped array to the + * provided reference. This allows losslessly converting between generic and typed virtual + * arrays in all cases. + * Return true when the virtual array was assigned and false when nothing was done. + */ + virtual bool try_assign_GVArray(fn::GVArray &UNUSED(varray)) const { + return false; } - void set(const int64_t index, T value) + /** + * Return true when this virtual array may own any of the memory it references. This can be used + * for optimization purposes when converting or copying the virtual array. + */ + virtual bool may_have_ownership() const { - BLI_assert(index >= 0); - BLI_assert(index < this->size_); - this->set_impl(index, std::move(value)); + /* Use true by default to be on the safe side. Subclasses that know for sure that they don't + * own anything can overwrite this with false. */ + return true; } +}; - /* Copy the values from the source span to all elements in the virtual array. */ - void set_all(Span<T> src) - { - BLI_assert(src.size() == this->size_); - this->set_all_impl(src); - } +/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ +template<typename T> class VMutableArrayImpl : public VArrayImpl<T> { + public: + using VArrayImpl<T>::VArrayImpl; - MutableSpan<T> get_internal_span() - { - BLI_assert(this->is_span()); - Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span(); - return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); - } + /** + * Assign the provided #value to the #index. + */ + virtual void set(const int64_t index, T value) = 0; - protected: - virtual void set_impl(const int64_t index, T value) = 0; - - virtual void set_all_impl(Span<T> src) + /** + * Copy all elements from the provided span into the virtual array. + */ + virtual void set_all(Span<T> src) { if (this->is_span()) { - const MutableSpan<T> span = this->get_internal_span(); + const Span<T> const_span = this->get_internal_span(); + const MutableSpan<T> span{(T *)const_span.data(), const_span.size()}; initialized_copy_n(src.data(), this->size_, span.data()); } else { @@ -253,95 +212,133 @@ template<typename T> class VMutableArray : public VArray<T> { } } } -}; -template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>; -template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>; + /** + * Similar to #VArrayImpl::try_assign_GVArray but for mutable virtual arrays. + */ + virtual bool try_assign_GVMutableArray(fn::GVMutableArray &UNUSED(varray)) const + { + return false; + } +}; /** * A virtual array implementation for a span. Methods in this class are final so that it can be * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used). */ -template<typename T> class VArray_For_Span : public VArray<T> { +template<typename T> class VArrayImpl_For_Span : public VArrayImpl<T> { protected: const T *data_ = nullptr; public: - VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data()) + VArrayImpl_For_Span(const Span<T> data) : VArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VArray_For_Span(const int64_t size) : VArray<T>(size) + VArrayImpl_For_Span(const int64_t size) : VArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - bool is_span_impl() const final + bool is_span() const final { return true; } - Span<T> get_internal_span_impl() const final + Span<T> get_internal_span() const final { return Span<T>(data_, this->size_); } }; -template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> { +/** + * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the + * #may_have_ownership method. + */ +template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> { + public: + using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * Like #VArrayImpl_For_Span but for mutable data. + */ +template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableArrayImpl<T> { protected: T *data_ = nullptr; public: - VMutableArray_For_MutableSpan(const MutableSpan<T> data) - : VMutableArray<T>(data.size()), data_(data.data()) + VMutableArrayImpl_For_MutableSpan(const MutableSpan<T> data) + : VMutableArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size) + VMutableArrayImpl_For_MutableSpan(const int64_t size) : VMutableArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { data_[index] = value; } - bool is_span_impl() const override + bool is_span() const override { return true; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(data_, this->size_); } }; /** - * A variant of `VArray_For_Span` that owns the underlying data. + * Like #VArrayImpl_For_Span_final but for mutable data. + */ +template<typename T> +class VMutableArrayImpl_For_MutableSpan_final final : public VMutableArrayImpl_For_MutableSpan<T> { + public: + using VMutableArrayImpl_For_MutableSpan<T>::VMutableArrayImpl_For_MutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * A variant of `VArrayImpl_For_Span` that owns the underlying data. * The `Container` type has to implement a `size()` and `data()` method. * The `data()` method has to return a pointer to the first element in the continuous array of * elements. */ template<typename Container, typename T = typename Container::value_type> -class VArray_For_ArrayContainer : public VArray_For_Span<T> { +class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> { private: Container container_; public: - VArray_For_ArrayContainer(Container container) - : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container)) + VArrayImpl_For_ArrayContainer(Container container) + : VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container)) { this->data_ = container_.data(); } @@ -352,43 +349,671 @@ class VArray_For_ArrayContainer : public VArray_For_Span<T> { * so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is * used). */ -template<typename T> class VArray_For_Single final : public VArray<T> { +template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> { private: T value_; public: - VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value)) + VArrayImpl_For_Single(T value, const int64_t size) + : VArrayImpl<T>(size), value_(std::move(value)) { } protected: - T get_impl(const int64_t UNUSED(index)) const override + T get(const int64_t UNUSED(index)) const override { return value_; } - bool is_span_impl() const override + bool is_span() const override { return this->size_ == 1; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(&value_, 1); } - bool is_single_impl() const override + bool is_single() const override { return true; } - T get_internal_single_impl() const override + T get_internal_single() const override { return value_; } }; /** + * This class makes it easy to create a virtual array for an existing function or lambda. The + * `GetFunc` should take a single `index` argument and return the value at that index. + */ +template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public VArrayImpl<T> { + private: + GetFunc get_func_; + + public: + VArrayImpl_For_Func(const int64_t size, GetFunc get_func) + : VArrayImpl<T>(size), get_func_(std::move(get_func)) + { + } + + private: + T get(const int64_t index) const override + { + return get_func_(index); + } + + void materialize(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> +class VArrayImpl_For_DerivedSpan final : public VArrayImpl<ElemT> { + private: + const StructT *data_; + + public: + VArrayImpl_For_DerivedSpan(const Span<StructT> data) + : VArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, ElemT)> +class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> { + private: + StructT *data_; + + public: + VMutableArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data) + : VMutableArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void set(const int64_t index, ElemT value) override + { + SetFunc(data_[index], std::move(value)); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +namespace detail { + +/** + * Struct that can be passed as `ExtraInfo` into an #Any. + * This struct is only intended to be used by #VArrayCommon. + */ +template<typename T> struct VArrayAnyExtraInfo { + /** + * Gets the virtual array that is stored at the given pointer. + */ + const VArrayImpl<T> *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; }; + + template<typename StorageT> static VArrayAnyExtraInfo get() + { + /* These are the only allowed types in the #Any. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> || + std::is_same_v<StorageT, const VArrayImpl<T> *> || + std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>); + + /* Depending on how the virtual array implementation is stored in the #Any, a different + * #get_varray function is required. */ + if constexpr (std::is_base_of_v<VArrayImpl<T>, StorageT>) { + return {[](const void *buffer) { + return static_cast<const VArrayImpl<T> *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const VArrayImpl<T> *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } + } +}; + +} // namespace detail + +/** + * Utility class to reduce code duplication for methods available on #VArray and #VMutableArray. + * Deriving #VMutableArray from #VArray would have some issues: + * - Static methods on #VArray would also be available on #VMutableArray. + * - It would allow assigning a #VArray to a #VMutableArray under some circumstances which is not + * allowed and could result in hard to find bugs. + */ +template<typename T> class VArrayCommon { + protected: + /** + * Store the virtual array implementation in an #Any. This makes it easy to avoid a memory + * allocation if the implementation is small enough and is copyable. This is the case for the + * most common virtual arrays. + * Other virtual array implementations are typically stored as #std::shared_ptr. That works even + * when the implementation itself is not copyable and makes copying #VArrayCommon cheaper. + */ + using Storage = Any<detail::VArrayAnyExtraInfo<T>, 24, 8>; + + /** + * Pointer to the currently contained virtual array implementation. This is allowed to be null. + */ + const VArrayImpl<T> *impl_ = nullptr; + /** + * Does the memory management for the virtual array implementation. It contains one of the + * following: + * - Inlined subclass of #VArrayImpl. + * - Non-owning pointer to a #VArrayImpl. + * - Shared pointer to a #VArrayImpl. + */ + Storage storage_; + + protected: + VArrayCommon() = default; + + /** Copy constructor. */ + VArrayCommon(const VArrayCommon &other) : storage_(other.storage_) + { + impl_ = this->impl_from_storage(); + } + + /** Move constructor. */ + VArrayCommon(VArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) + { + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** + * Wrap an existing #VArrayImpl and don't take ownership of it. This should rarely be used in + * practice. + */ + VArrayCommon(const VArrayImpl<T> *impl) : impl_(impl) + { + storage_ = impl_; + } + + /** + * Wrap an existing #VArrayImpl that is contained in a #std::shared_ptr. This takes ownership. + */ + VArrayCommon(std::shared_ptr<const VArrayImpl<T>> impl) : impl_(impl.get()) + { + if (impl) { + storage_ = std::move(impl); + } + } + + /** + * Replace the contained #VArrayImpl. + */ + template<typename ImplT, typename... Args> void emplace(Args &&...args) + { + /* Make sure we are actually constructing a #VArrayImpl. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + /* Only inline the implementatiton when it is copyable and when it fits into the inline + * buffer of the storage. */ + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + /* If it can't be inlined, create a new #std::shared_ptr instead and store that in the + * storage. */ + std::shared_ptr<const VArrayImpl<T>> ptr = std::make_shared<ImplT>( + std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } + } + + /** Utility to implement a copy assignment operator in a subclass. */ + void copy_from(const VArrayCommon &other) + { + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); + } + + /** Utility to implement a move assignment operator in a subclass. */ + void move_from(VArrayCommon &&other) noexcept + { + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** Get a pointer to the virtual array implementation that is currently stored in #storage_, or + * null. */ + const VArrayImpl<T> *impl_from_storage() const + { + return storage_.extra_info().get_varray(storage_.get()); + } + + public: + /** Return false when there is no virtual array implementation currently. */ + operator bool() const + { + return impl_ != nullptr; + } + + /** + * Get the element at a specific index. + * \note: This can't return a reference because the value may be computed on the fly. This also + * implies that one can not use this method for assignments. + */ + T operator[](const int64_t index) const + { + BLI_assert(*this); + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + return impl_->get(index); + } + + /** + * Same as the #operator[] but is sometimes easier to use when one has a pointer to a virtual + * array. + */ + T get(const int64_t index) const + { + return (*this)[index]; + } + + /** + * Return the size of the virtual array. It's allowed to call this method even when there is no + * virtual array. In this case 0 is returned. + */ + int64_t size() const + { + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); + } + + /** True when the size is zero or when there is no virtual array. */ + bool is_empty() const + { + return this->size() == 0; + } + + IndexRange index_range() const + { + return IndexRange(this->size()); + } + + /** Return true when the virtual array is stored as a span internally. */ + bool is_span() const + { + BLI_assert(*this); + if (this->is_empty()) { + return true; + } + return impl_->is_span(); + } + + /** + * Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. + */ + Span<T> get_internal_span() const + { + BLI_assert(this->is_span()); + if (this->is_empty()) { + return {}; + } + return impl_->get_internal_span(); + } + + /** Return true when the virtual array returns the same value for every index. */ + bool is_single() const + { + BLI_assert(*this); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); + } + + /** + * Return the value that is returned for every index. This invokes undefined behavior if the + * virtual array would not return the same value for every index. + */ + T get_internal_single() const + { + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + return impl_->get(0); + } + return impl_->get_internal_single(); + } + + /** Copy the entire virtual array into a span. */ + void materialize(MutableSpan<T> r_span) const + { + this->materialize(IndexMask(this->size()), r_span); + } + + /** Copy some indices of the virtual array into a span. */ + void materialize(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize(mask, r_span); + } + + void materialize_to_uninitialized(MutableSpan<T> r_span) const + { + this->materialize_to_uninitialized(IndexMask(this->size()), r_span); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize_to_uninitialized(mask, r_span); + } + + /** See #GVArrayImpl::try_assign_GVArray. */ + bool try_assign_GVArray(fn::GVArray &varray) const + { + return impl_->try_assign_GVArray(varray); + } + + /** See #GVArrayImpl::may_have_ownership. */ + bool may_have_ownership() const + { + return impl_->may_have_ownership(); + } +}; + +template<typename T> class VMutableArray; + +/** + * A #VArray wraps a virtual array implementation and provides easy access to its elements. It can + * be copied and moved. While it is relatively small, it should still be passed by reference if + * possible (other than e.g. #Span). + */ +template<typename T> class VArray : public VArrayCommon<T> { + friend VMutableArray<T>; + + public: + VArray() = default; + VArray(const VArray &other) = default; + VArray(VArray &&other) noexcept = default; + + VArray(const VArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VArrayImpl. + */ + template<typename ImplT, typename... Args> static VArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + VArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array that has the same value at every index. + */ + static VArray ForSingle(T value, const int64_t size) + { + return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size); + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the + * underlying memory. + */ + static VArray ForSpan(Span<T> values) + { + return VArray::For<VArrayImpl_For_Span_final<T>>(values); + } + + /** + * Construct a new virtual that will invoke the provided function whenever an element is + * accessed. + */ + template<typename GetFunc> static VArray ForFunc(const int64_t size, GetFunc get_func) + { + return VArray::For<VArrayImpl_For_Func<T, decltype(get_func)>>(size, std::move(get_func)); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &)> + static VArray ForDerivedSpan(Span<StructT> values) + { + return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(values); + } + + /** + * Construct a new virtual array for an existing container. Every container that lays out the + * elements in a plain array works. This takes ownership of the passed in container. If that is + * not desired, use #ForSpan instead. + */ + template<typename ContainerT> static VArray ForContainer(ContainerT container) + { + return VArray::For<VArrayImpl_For_ArrayContainer<ContainerT>>(std::move(container)); + } + + VArray &operator=(const VArray &other) + { + this->copy_from(other); + return *this; + } + + VArray &operator=(VArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } +}; + +/** + * Similar to #VArray but references a virtual array that can be modified. + */ +template<typename T> class VMutableArray : public VArrayCommon<T> { + public: + VMutableArray() = default; + VMutableArray(const VMutableArray &other) = default; + VMutableArray(VMutableArray &&other) noexcept = default; + + VMutableArray(const VMutableArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VMutableArray(std::shared_ptr<const VMutableArrayImpl<T>> impl) + : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VMutableArrayImpl. + */ + template<typename ImplT, typename... Args> static VMutableArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VMutableArrayImpl<T>, ImplT>); + VMutableArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the span. + */ + static VMutableArray ForSpan(MutableSpan<T> values) + { + return VMutableArray::For<VMutableArrayImpl_For_MutableSpan_final<T>>(values); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)> + static VMutableArray ForDerivedSpan(MutableSpan<StructT> values) + { + return VMutableArray::For<VMutableArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>( + values); + } + + /** Convert to a #VArray by copying. */ + operator VArray<T>() const & + { + VArray<T> varray; + varray.copy_from(*this); + return varray; + } + + /** Convert to a #VArray by moving. */ + operator VArray<T>() &&noexcept + { + VArray<T> varray; + varray.move_from(std::move(*this)); + return varray; + } + + VMutableArray &operator=(const VMutableArray &other) + { + this->copy_from(other); + return *this; + } + + VMutableArray &operator=(VMutableArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } + + /** + * Get access to the internal span. This invokes undefined behavior if the #is_span returned + * false. + */ + MutableSpan<T> get_internal_span() const + { + BLI_assert(this->is_span()); + const Span<T> span = this->impl_->get_internal_span(); + return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); + } + + /** + * Set the value at the given index. + */ + void set(const int64_t index, T value) + { + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set(index, std::move(value)); + } + + /** + * Copy the values from the source span to all elements in the virtual array. + */ + void set_all(Span<T> src) + { + BLI_assert(src.size() == this->size()); + this->get_impl()->set_all(src); + } + + /** See #GVMutableArrayImpl::try_assign_GVMutableArray. */ + bool try_assign_GVMutableArray(fn::GVMutableArray &varray) const + { + return this->get_impl()->try_assign_GVMutableArray(varray); + } + + private: + /** Utility to get the pointer to the wrapped #VMutableArrayImpl. */ + VMutableArrayImpl<T> *get_impl() const + { + /* This cast is valid by the invariant that a #VMutableArray->impl_ is always a + * #VMutableArrayImpl. */ + return (VMutableArrayImpl<T> *)this->impl_; + } +}; + +/** * In many cases a virtual array is a span internally. In those cases, access to individual could * be much more efficient than calling a virtual method. When the underlying virtual array is not a * span, this class allocates a new array and copies the values over. @@ -401,11 +1026,11 @@ template<typename T> class VArray_For_Single final : public VArray<T> { */ template<typename T> class VArray_Span final : public Span<T> { private: - const VArray<T> &varray_; + VArray<T> varray_; Array<T> owned_data_; public: - VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray) + VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -421,7 +1046,7 @@ template<typename T> class VArray_Span final : public Span<T> { }; /** - * Same as VArray_Span, but for a mutable span. + * Same as #VArray_Span, but for a mutable span. * The important thing to note is that when changing this span, the results might not be * immediately reflected in the underlying virtual array (only when the virtual array is a span * internally). The #save method can be used to write all changes to the underlying virtual array, @@ -429,7 +1054,7 @@ template<typename T> class VArray_Span final : public Span<T> { */ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { private: - VMutableArray<T> &varray_; + VMutableArray<T> varray_; Array<T> owned_data_; bool save_has_been_called_ = false; bool show_not_saved_warning_ = true; @@ -437,8 +1062,8 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { public: /* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If * not, a new array has to be allocated as a wrapper for the underlying virtual array. */ - VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true) - : MutableSpan<T>(), varray_(varray) + VMutableArray_Span(VMutableArray<T> varray, const bool copy_values_to_span = true) + : MutableSpan<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -483,106 +1108,6 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { }; /** - * This class makes it easy to create a virtual array for an existing function or lambda. The - * `GetFunc` should take a single `index` argument and return the value at that index. - */ -template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> { - private: - GetFunc get_func_; - - public: - VArray_For_Func(const int64_t size, GetFunc get_func) - : VArray<T>(size), get_func_(std::move(get_func)) - { - } - - private: - T get_impl(const int64_t index) const override - { - return get_func_(index); - } - - void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); - } -}; - -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class VArray_For_DerivedSpan : public VArray<ElemT> { - private: - const StructT *data_; - - public: - VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> { - private: - StructT *data_; - - public: - VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : VMutableArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void set_impl(const int64_t index, ElemT value) override - { - SetFunc(data_[index], std::move(value)); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -/** * Generate multiple versions of the given function optimized for different virtual arrays. * One has to be careful with nesting multiple devirtualizations, because that results in an * exponential number of function instantiations (increasing compile time and binary size). @@ -596,15 +1121,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool /* Support disabling the devirtualization to simplify benchmarking. */ if (enable) { if (varray.is_single()) { - /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()}; - func(varray_single); + /* `VArrayImpl_For_Single` can be used for devirtualization, because it is declared `final`. + */ + func(VArray<T>::ForSingle(varray.get_internal_single(), varray.size())); return; } if (varray.is_span()) { - /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Span<T> varray_span{varray.get_internal_span()}; - func(varray_span); + /* `VArrayImpl_For_Span` can be used for devirtualization, because it is declared `final`. */ + func(VArray<T>::ForSpan(varray.get_internal_span())); return; } } @@ -629,27 +1153,23 @@ inline void devirtualize_varray2(const VArray<T1> &varray1, const bool is_single1 = varray1.is_single(); const bool is_single2 = varray2.is_single(); if (is_span1 && is_span2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_span, varray2_span); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_span1 && is_single2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_span, varray2_single); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } if (is_single1 && is_span2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_single, varray2_span); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_single1 && is_single2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_single, varray2_single); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } } diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 7db984aef5c..29493c799b3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -165,6 +165,7 @@ set(SRC BLI_alloca.h BLI_allocator.hh + BLI_any.hh BLI_args.h BLI_array.h BLI_array.hh @@ -411,6 +412,7 @@ blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC + tests/BLI_any_test.cc tests/BLI_array_store_test.cc tests/BLI_array_test.cc tests/BLI_array_utils_test.cc diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index f968799326a..bd6a124c7cb 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -126,7 +126,7 @@ struct BLI_mempool { uint flag; /* keeps aligned to 16 bits */ - /** Free element list. Interleaved into chunk datas. */ + /** Free element list. Interleaved into chunk data. */ BLI_freenode *free; /** Use to know how many chunks to keep for #BLI_mempool_clear. */ uint maxchunks; diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index e8be674b6c1..62c8625378d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1346,9 +1346,8 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base } /** - * Format a attribute domain to a up to 6 places (plus '\0' terminator) string using long number - * names abbreviations. This function is designed to produce a compact representation of large - * numbers. + * Format a count to up to 6 places (plus '\0' terminator) string using long number + * names abbreviations. Used to produce a compact representation of large numbers. * * 1 -> 1 * 15 -> 15 @@ -1362,8 +1361,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base * 1000000000 -> 1B * ... * - * Dimension of 7 is the maximum length of the resulting string - * A combination with 7 places would be -15.5K\0 + * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`. */ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) { diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc new file mode 100644 index 00000000000..226088cf3c7 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_any_test.cc @@ -0,0 +1,108 @@ +/* Apache License, Version 2.0 */ + +#include "BLI_any.hh" +#include "BLI_map.hh" + +#include "testing/testing.h" + +namespace blender::tests { + +TEST(any, DefaultConstructor) +{ + Any a; + EXPECT_FALSE(a.has_value()); +} + +TEST(any, AssignInt) +{ + Any<> a = 5; + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE(a.is<int>()); + EXPECT_FALSE(a.is<float>()); + const int &value = a.get<int>(); + EXPECT_EQ(value, 5); + a = 10; + EXPECT_EQ(value, 10); + + Any b = a; + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(b.get<int>(), 10); + + Any c = std::move(a); + EXPECT_TRUE(c); + EXPECT_EQ(c.get<int>(), 10); + + EXPECT_EQ(a.get<int>(), 10); /* NOLINT: bugprone-use-after-move */ + + a.reset(); + EXPECT_FALSE(a); +} + +TEST(any, AssignMap) +{ + Any<> a = Map<int, int>(); + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE((a.is<Map<int, int>>())); + EXPECT_FALSE((a.is<Map<int, float>>())); + Map<int, int> &map = a.get<Map<int, int>>(); + map.add(4, 2); + EXPECT_EQ((a.get<Map<int, int>>().lookup(4)), 2); + + Any b = a; + EXPECT_TRUE(b); + EXPECT_EQ((b.get<Map<int, int>>().lookup(4)), 2); + + Any c = std::move(a); + c = c; + EXPECT_TRUE(b); + EXPECT_EQ((c.get<Map<int, int>>().lookup(4)), 2); + + EXPECT_TRUE((a.get<Map<int, int>>().is_empty())); /* NOLINT: bugprone-use-after-move */ +} + +TEST(any, AssignAny) +{ + Any<> a = 5; + Any<> b = std::string("hello"); + Any c; + + Any z; + EXPECT_FALSE(z.has_value()); + + z = a; + EXPECT_TRUE(z.has_value()); + EXPECT_EQ(z.get<int>(), 5); + + z = b; + EXPECT_EQ(z.get<std::string>(), "hello"); + + z = c; + EXPECT_FALSE(z.has_value()); + + z = Any(std::in_place_type<Any<>>, a); + EXPECT_FALSE(z.is<int>()); + EXPECT_TRUE(z.is<Any<>>()); + EXPECT_EQ(z.get<Any<>>().get<int>(), 5); +} + +struct ExtraSizeInfo { + size_t size; + + template<typename T> static ExtraSizeInfo get() + { + return {sizeof(T)}; + } +}; + +TEST(any, ExtraInfo) +{ + using MyAny = Any<ExtraSizeInfo>; + + MyAny a = 5; + EXPECT_EQ(a.extra_info().size, sizeof(int)); + + a = std::string("hello"); + EXPECT_EQ(a.extra_info().size, sizeof(std::string)); +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc index a6d2ca10315..62b7b383831 100644 --- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc +++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc @@ -12,7 +12,7 @@ namespace blender::tests { TEST(virtual_array, Span) { std::array<int, 5> data = {3, 4, 5, 6, 7}; - VArray_For_Span<int> varray{data}; + VArray<int> varray = VArray<int>::ForSpan(data); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray.get(0), 3); EXPECT_EQ(varray.get(4), 7); @@ -23,7 +23,7 @@ TEST(virtual_array, Span) TEST(virtual_array, Single) { - VArray_For_Single<int> varray{10, 4}; + VArray<int> varray = VArray<int>::ForSingle(10, 4); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray.get(0), 10); EXPECT_EQ(varray.get(3), 10); @@ -35,7 +35,7 @@ TEST(virtual_array, Array) { Array<int> array = {1, 2, 3, 5, 8}; { - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(array); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -43,7 +43,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{std::move(array)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -51,7 +51,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */ + VArray<int> varray = VArray<int>::ForContainer(array); /* NOLINT: bugprone-use-after-move */ EXPECT_TRUE(varray.is_empty()); } } @@ -59,7 +59,7 @@ TEST(virtual_array, Array) TEST(virtual_array, Vector) { Vector<int> vector = {9, 8, 7, 6}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 9); EXPECT_EQ(varray[3], 6); @@ -68,7 +68,7 @@ TEST(virtual_array, Vector) TEST(virtual_array, StdVector) { std::vector<int> vector = {5, 6, 7, 8}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); EXPECT_EQ(varray[1], 6); @@ -77,7 +77,7 @@ TEST(virtual_array, StdVector) TEST(virtual_array, StdArray) { std::array<int, 4> array = {2, 3, 4, 5}; - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 2); EXPECT_EQ(varray[1], 3); @@ -86,7 +86,7 @@ TEST(virtual_array, StdArray) TEST(virtual_array, VectorSet) { VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1}; - VArray_For_ArrayContainer varray{std::move(vector_set)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector_set)); EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */ EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); @@ -98,7 +98,7 @@ TEST(virtual_array, VectorSet) TEST(virtual_array, Func) { auto func = [](int64_t index) { return (int)(index * index); }; - VArray_For_Func<int, decltype(func)> varray{10, func}; + VArray<int> varray = VArray<int>::ForFunc(10, func); EXPECT_EQ(varray.size(), 10); EXPECT_EQ(varray[0], 0); EXPECT_EQ(varray[3], 9); @@ -108,7 +108,7 @@ TEST(virtual_array, Func) TEST(virtual_array, AsSpan) { auto func = [](int64_t index) { return (int)(10 * index); }; - VArray_For_Func<int, decltype(func)> func_varray{10, func}; + VArray<int> func_varray = VArray<int>::ForFunc(10, func); VArray_Span span_varray{func_varray}; EXPECT_EQ(span_varray.size(), 10); Span<int> span = span_varray; @@ -134,13 +134,14 @@ TEST(virtual_array, DerivedSpan) vector.append({3, 4, 5}); vector.append({1, 1, 1}); { - VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector}; + VArray<int> varray = VArray<int>::ForDerivedSpan<std::array<int, 3>, get_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); } { - VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector}; + VMutableArray<int> varray = + VMutableArray<int>::ForDerivedSpan<std::array<int, 3>, get_x, set_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); @@ -151,4 +152,32 @@ TEST(virtual_array, DerivedSpan) } } +TEST(virtual_array, MutableToImmutable) +{ + std::array<int, 4> array = {4, 2, 6, 4}; + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + VArray<int> varray = mutable_varray; + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 4); + } + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + EXPECT_EQ(mutable_varray.size(), 4); + VArray<int> varray = std::move(mutable_varray); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 0); /* NOLINT: bugprone-use-after-move */ + } + { + VArray<int> varray = VMutableArray<int>::ForSpan(array); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + } +} + } // namespace blender::tests diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 22182edd070..e3a8fd2bf3f 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -241,7 +241,7 @@ typedef enum eBLOLibLinkFlags { * #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end. * Wrap these in parameters since it's important both functions receive matching values. */ -struct LibraryLink_Params { +typedef struct LibraryLink_Params { /** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */ struct Main *bmain; /** Options for linking, used for instantiating. */ @@ -257,7 +257,7 @@ struct LibraryLink_Params { /** The active 3D viewport (only used to define local-view). */ const struct View3D *v3d; } context; -}; +} LibraryLink_Params; void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 3306eb9e454..c0fdfa86907 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -347,6 +347,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_ case ID_GR: /* fall through */ case ID_SCE: /* fall through */ case ID_AC: /* fall through */ + case ID_NT: /* fall through */ new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview"); BLI_linklist_prepend(&previews, new_prv); tot++; diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 940a10a9e91..822ef2cda8d 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1279,6 +1279,18 @@ static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree) } } +static void version_node_tree_socket_id_delim(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + version_node_socket_id_delim(socket); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + version_node_socket_id_delim(socket); + } + } +} + static bool version_fix_seq_meta_range(Sequence *seq, void *user_data) { Scene *scene = (Scene *)user_data; @@ -2308,35 +2320,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) { - /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, - * constraints and NLA tracks). */ - ID *id_iter; - FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { - version_liboverride_rnacollections_insertion_animdata(id_iter); - if (GS(id_iter->name) == ID_OB) { - version_liboverride_rnacollections_insertion_object((Object *)id_iter); - } - } - } - FOREACH_MAIN_ID_END; - /* Use consistent socket identifiers for the math node. * The code to make unique identifiers from the names was inconsistent. */ FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY)) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->type == SH_NODE_MATH) { - bNodeSocket *value1 = ((bNodeSocket *)node->inputs.first)->next; - bNodeSocket *value2 = value1->next; - strcpy(value1->identifier, "Value_001"); - if (value2 != NULL) { - /* This can be null when file is quite old so that the socket did not exist - * (before 0406eb110332a8). */ - strcpy(value2->identifier, "Value_002"); - } - } - } + if (ntree->type != NTREE_CUSTOM) { + version_node_tree_socket_id_delim(ntree); } } FOREACH_NODETREE_END; @@ -2357,6 +2345,25 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Change minimum zoom to 0.05f in the node editor. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW) { + if (region->v2d.minzoom > 0.05f) { + region->v2d.minzoom = 0.05f; + } + } + } + } + } + } + } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { Editing *ed = SEQ_editing_get(scene); /* Make sure range of meta strips is correct. @@ -2369,6 +2376,24 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in + * master. */ + if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) || + (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) { + /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, + * constraints and NLA tracks). */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { + version_liboverride_rnacollections_insertion_animdata(id_iter); + if (GS(id_iter->name) == ID_OB) { + version_liboverride_rnacollections_insertion_object((Object *)id_iter); + } + } + } + FOREACH_MAIN_ID_END; + } + /** * Versioning code until next subversion bump goes here. * @@ -2379,5 +2404,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) * \note Keep this message at the bottom of the function. */ { + /* Keep this block, even when empty. */ } } diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index c7ff496fa20..af765be619f 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -27,6 +27,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BKE_animsys.h" #include "BKE_lib_id.h" @@ -37,6 +38,8 @@ #include "versioning_common.h" +using blender::StringRef; + ARegion *do_versions_add_region_if_not_found(ListBase *regionbase, int region_type, const char *name, @@ -101,6 +104,30 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con } } +/** + * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used. + */ +void version_node_socket_id_delim(bNodeSocket *socket) +{ + StringRef name = socket->name; + StringRef id = socket->identifier; + + if (!id.startswith(name)) { + /* We only need to affect the case where the identifier starts with the name. */ + return; + } + + StringRef id_number = id.drop_known_prefix(name); + if (id_number.is_empty()) { + /* The name was already unique, and didn't need numbers at the end for the id. */ + return; + } + + if (id_number.startswith(".")) { + socket->identifier[name.size()] = '_'; + } +} + void version_node_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, @@ -127,9 +154,9 @@ void version_node_input_socket_name(bNodeTree *ntree, } void version_node_output_socket_name(bNodeTree *ntree, - const int node_type, - const char *old_name, - const char *new_name) + const int node_type, + const char *old_name, + const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index ed1cafdca33..7f179800ddd 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -62,6 +62,8 @@ void version_node_socket_index_animdata( void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name); +void version_node_socket_id_delim(bNodeSocket *socket); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 809adc493f4..0e5e0b76f43 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -321,14 +321,22 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->space_node.grid_levels = 7; } - if (!USER_VERSION_ATLEAST(300, 40)) { + if (!USER_VERSION_ATLEAST(300, 41)) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } - if (!USER_VERSION_ATLEAST(300, 41)) { + /* Again reset the theme, but only if stored with an early 3.1 alpha version. Some changes were + * done in the release branch and then merged into the 3.1 branch (master). So the previous reset + * wouldn't work for people who saved their preferences with a 3.1 build meanwhile. But we still + * don't want to reset theme changes stored in the eventual 3.0 release once opened in a 3.1 + * build. */ + if (userdef->versionfile > 300 && !USER_VERSION_ATLEAST(301, 1)) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } + if (!USER_VERSION_ATLEAST(301, 2)) { + FROM_DEFAULT_V4_UCHAR(space_sequencer.mask); + } /** * Versioning code until next subversion bump goes here. * @@ -704,8 +712,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 38)) { - - /* (keep this block even if it becomes empty). */ copy_v4_fl4(userdef->light_param[0].vec, -0.580952, 0.228571, 0.781185, 0.0); copy_v4_fl4(userdef->light_param[0].col, 0.900000, 0.900000, 0.900000, 1.000000); copy_v4_fl4(userdef->light_param[0].spec, 0.318547, 0.318547, 0.318547, 1.000000); @@ -738,8 +744,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 41)) { - /* (keep this block even if it becomes empty). */ - if (userdef->pie_tap_timeout == 0) { userdef->pie_tap_timeout = 20; } @@ -796,7 +800,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 62)) { - /* (keep this block even if it becomes empty). */ if (userdef->vbotimeout == 0) { userdef->vbocollectrate = 60; userdef->vbotimeout = 120; diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index 21156868655..a4a5ced070d 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -67,7 +67,6 @@ void BlendfileLoadingBaseTest::SetUpTestCase() BKE_idtype_init(); BKE_appdir_init(); IMB_init(); - BKE_images_init(); BKE_modifier_init(); DEG_register_node_types(); RNA_init(); diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index da4567d947b..f366aede2ab 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -85,7 +85,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) } if (ok) { - /* NOTE: in the case of multiple loops, this over-allocs (which is fine). */ + /* NOTE: in the case of multiple loops, this over-allocates (which is fine). */ BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__); BMIter eiter; diff --git a/source/blender/bmesh/tests/bmesh_core_test.cc b/source/blender/bmesh/tests/bmesh_core_test.cc index 202d16b09e3..3d6fabcbc2f 100644 --- a/source/blender/bmesh/tests/bmesh_core_test.cc +++ b/source/blender/bmesh/tests/bmesh_core_test.cc @@ -10,9 +10,9 @@ TEST(bmesh_core, BMVertCreate) BMVert *bv1, *bv2, *bv3; const float co1[3] = {1.0f, 2.0f, 0.0f}; - BMeshCreateParams bm_params; - bm_params.use_toolflags = true; - bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params); + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; + bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params); EXPECT_EQ(bm->totvert, 0); /* make a custom layer so we can see if it is copied properly */ BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLOAT); diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index 354997ebd2e..696dbb1807c 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -155,7 +155,7 @@ void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number* if (rd->mode & R_BORDER && rd->mode & R_CROP) { /** * When using cropped render result, need to re-position area of interest, - * so it'll natch bounds of render border within frame. By default, canvas + * so it'll match bounds of render border within frame. By default, canvas * will be centered between full frame and cropped frame, so we use such * scheme to map cropped coordinates to full-frame coordinates * diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 0baf994d978..b8ca22d33d3 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -112,8 +112,9 @@ set(SRC intern/draw_view_data.cc intern/smaa_textures.c engines/basic/basic_engine.c - engines/image/image_engine.c - engines/image/image_shader.c + engines/basic/basic_shader.c + engines/image/image_engine.cc + engines/image/image_shader.cc engines/eevee/eevee_bloom.c engines/eevee/eevee_cryptomatte.c engines/eevee/eevee_data.c @@ -214,13 +215,14 @@ set(SRC intern/mesh_extractors/extract_mesh.h intern/smaa_textures.h engines/basic/basic_engine.h + engines/basic/basic_private.h engines/eevee/eevee_engine.h engines/eevee/eevee_lightcache.h engines/eevee/eevee_lut.h engines/eevee/eevee_private.h engines/external/external_engine.h engines/image/image_engine.h - engines/image/image_private.h + engines/image/image_private.hh engines/workbench/workbench_engine.h engines/workbench/workbench_private.h engines/select/select_engine.h diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index f4fdb9d0912..8a825a7c81f 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -36,17 +36,10 @@ #include "GPU_shader.h" #include "basic_engine.h" -/* Shaders */ +#include "basic_private.h" #define BASIC_ENGINE "BLENDER_BASIC" -extern char datatoc_depth_frag_glsl[]; -extern char datatoc_depth_vert_glsl[]; -extern char datatoc_conservative_depth_geom_glsl[]; - -extern char datatoc_common_view_lib_glsl[]; -extern char datatoc_common_pointcloud_lib_glsl[]; - /* *********** LISTS *********** */ /* GPUViewport.storage @@ -69,20 +62,8 @@ typedef struct BASIC_Data { BASIC_StorageList *stl; } BASIC_Data; -typedef struct BASIC_Shaders { - /* Depth Pre Pass */ - struct GPUShader *depth; - struct GPUShader *pointcloud_depth; - struct GPUShader *depth_conservative; - struct GPUShader *pointcloud_depth_conservative; -} BASIC_Shaders; - /* *********** STATIC *********** */ -static struct { - BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]; -} e_data = {{{NULL}}}; /* Engine data */ - typedef struct BASIC_PrivateData { DRWShadingGroup *depth_shgrp[2]; DRWShadingGroup *depth_shgrp_cull[2]; @@ -91,74 +72,6 @@ typedef struct BASIC_PrivateData { bool use_material_slot_selection; } BASIC_PrivateData; /* Transient data */ -/* Functions */ - -static void basic_engine_init(void *UNUSED(vedata)) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - - /* Depth prepass */ - if (!sh_data->depth) { - const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; - - sh_data->depth = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, - }); - - sh_data->pointcloud_depth = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_common_pointcloud_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, - "#define POINTCLOUD\n", - "#define INSTANCED_ATTR\n", - "#define UNIFORM_RESOURCE_ID\n", - NULL}, - }); - - sh_data->depth_conservative = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .geom = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_conservative_depth_geom_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, - }); - - sh_data->pointcloud_depth_conservative = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_common_pointcloud_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .geom = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_conservative_depth_geom_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, - "#define CONSERVATIVE_RASTER\n", - "#define POINTCLOUD\n", - "#define INSTANCED_ATTR\n", - "#define UNIFORM_RESOURCE_ID\n", - NULL}, - }); - } -} - static void basic_cache_init(void *vedata) { BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl; @@ -166,7 +79,6 @@ static void basic_cache_init(void *vedata) DRWShadingGroup *grp; const DRWContextState *draw_ctx = DRW_context_state_get(); - BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (!stl->g_data) { /* Alloc transient pointers */ @@ -181,24 +93,29 @@ static void basic_cache_init(void *vedata) DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - GPUShader *sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth; + GPUShader *sh = DRW_state_is_select() ? + BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg); DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state); stl->g_data->depth_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass[i]); DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1); - sh = DRW_state_is_select() ? sh_data->pointcloud_depth_conservative : sh_data->pointcloud_depth; + sh = DRW_state_is_select() ? + BASIC_shaders_pointcloud_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_pointcloud_depth_sh_get(draw_ctx->sh_cfg); DRW_PASS_CREATE(psl->depth_pass_pointcloud[i], state | clip_state | infront_state); - stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_pointcloud[i]); + stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create( + sh, psl->depth_pass_pointcloud[i]); DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1); - stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(sh_data->depth, - psl->depth_pass[i]); + stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create( + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg), psl->depth_pass[i]); - - sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth; + sh = DRW_state_is_select() ? BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg); state |= DRW_STATE_CULL_BACK; DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state); stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]); @@ -336,13 +253,7 @@ static void basic_draw_scene(void *vedata) static void basic_engine_free(void) { - for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { - BASIC_Shaders *sh_data = &e_data.sh_data[i]; - DRW_SHADER_FREE_SAFE(sh_data->depth); - DRW_SHADER_FREE_SAFE(sh_data->depth_conservative); - DRW_SHADER_FREE_SAFE(sh_data->pointcloud_depth); - DRW_SHADER_FREE_SAFE(sh_data->pointcloud_depth_conservative); - } + BASIC_shaders_free(); } static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data); @@ -352,7 +263,7 @@ DrawEngineType draw_engine_basic_type = { NULL, N_("Basic"), &basic_data_size, - &basic_engine_init, + NULL, &basic_engine_free, &basic_cache_init, &basic_cache_populate, diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/basic/basic_private.h index 76a94e68da1..e5f494bf0e7 100644 --- a/source/blender/draw/engines/image/image_private.h +++ b/source/blender/draw/engines/basic/basic_private.h @@ -24,45 +24,11 @@ extern "C" { #endif -/* Forward declarations */ -struct GPUTexture; -struct ImBuf; -struct Image; - -/* *********** LISTS *********** */ - -/* GPUViewport.storage - * Is freed every time the viewport engine changes. */ -typedef struct IMAGE_PassList { - DRWPass *image_pass; -} IMAGE_PassList; - -typedef struct IMAGE_PrivateData { - void *lock; - struct ImBuf *ibuf; - struct Image *image; - struct DRWView *view; - - struct GPUTexture *texture; - bool owns_texture; -} IMAGE_PrivateData; - -typedef struct IMAGE_StorageList { - IMAGE_PrivateData *pd; -} IMAGE_StorageList; - -typedef struct IMAGE_Data { - void *engine_type; - DRWViewportEmptyList *fbl; - DRWViewportEmptyList *txl; - IMAGE_PassList *psl; - IMAGE_StorageList *stl; -} IMAGE_Data; - -/* image_shader.c */ -GPUShader *IMAGE_shader_image_get(bool is_tiled_image); -void IMAGE_shader_library_ensure(void); -void IMAGE_shader_free(void); +GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config); +void BASIC_shaders_free(void); #ifdef __cplusplus } diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c new file mode 100644 index 00000000000..4b92406d5c0 --- /dev/null +++ b/source/blender/draw/engines/basic/basic_shader.c @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "GPU_shader.h" + +#include "basic_private.h" + +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; +extern char datatoc_conservative_depth_geom_glsl[]; + +extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_pointcloud_lib_glsl[]; + +/* Shaders */ + +typedef struct BASIC_Shaders { + /* Depth Pre Pass */ + struct GPUShader *depth; + struct GPUShader *pointcloud_depth; + struct GPUShader *depth_conservative; + struct GPUShader *pointcloud_depth_conservative; +} BASIC_Shaders; + +static struct { + BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]; +} e_data = {{{NULL}}}; /* Engine data */ + +static GPUShader *BASIC_shader_create_depth_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); +} + +static GPUShader *BASIC_shader_create_pointcloud_depth_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_common_pointcloud_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define POINTCLOUD\n", + "#define INSTANCED_ATTR\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); +} + +static GPUShader *BASIC_shader_create_depth_conservative_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_conservative_depth_geom_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, + }); +} + +static GPUShader *BASIC_shader_create_pointcloud_depth_conservative_sh( + const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_common_pointcloud_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_conservative_depth_geom_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define CONSERVATIVE_RASTER\n", + "#define POINTCLOUD\n", + "#define INSTANCED_ATTR\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); +} + +GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->depth == NULL) { + sh_data->depth = BASIC_shader_create_depth_sh(sh_cfg); + } + return sh_data->depth; +} + +GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->pointcloud_depth == NULL) { + sh_data->pointcloud_depth = BASIC_shader_create_pointcloud_depth_sh(sh_cfg); + } + return sh_data->pointcloud_depth; +} + +GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->depth_conservative == NULL) { + sh_data->depth_conservative = BASIC_shader_create_depth_conservative_sh(sh_cfg); + } + return sh_data->depth_conservative; +} + +GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->pointcloud_depth_conservative == NULL) { + sh_data->pointcloud_depth_conservative = BASIC_shader_create_pointcloud_depth_conservative_sh( + sh_cfg); + } + return sh_data->pointcloud_depth_conservative; +} + +void BASIC_shaders_free(void) +{ + for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { + GPUShader **sh_data_as_array = (GPUShader **)&e_data.sh_data[i]; + for (int j = 0; j < (sizeof(BASIC_Shaders) / sizeof(GPUShader *)); j++) { + DRW_SHADER_FREE_SAFE(sh_data_as_array[j]); + } + } +} diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 93641443cac..41d6db7f726 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -56,7 +56,7 @@ vec2 get_ao_noise(void) { vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; /* Decorrelate noise from AA. */ - /* TODO(fclem) we should use a more general approach for more random number dimentions. */ + /* TODO(fclem) we should use a more general approach for more random number dimensions. */ noise = fract(noise * 6.1803402007); return noise; } @@ -399,7 +399,7 @@ float specular_occlusion( /* Use the right occlusion. */ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) { - /* Default to fully openned cone. */ + /* Default to fully opened cone. */ OcclusionData data = NO_OCCLUSION_DATA; #ifdef ENABLE_DEFERED_AO diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl index e5cbc487e93..311887cf2f5 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl @@ -172,7 +172,7 @@ /* -------------------------------------------------------------------- */ /** \name Common cl_eval data * - * Eval data not dependant on input parameters. All might not be used but unused ones + * Eval data not dependent on input parameters. All might not be used but unused ones * will be optimized out. * \{ */ @@ -240,7 +240,7 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in) /* -------------------------------------------------------------------- */ /** \name Loop data * - * Loop datas are conveniently packed into struct to make it future proof. + * Loop data is conveniently packed into struct to make it future proof. * \{ */ struct ClosureLightData { diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index c3325ec4286..77a1560f3a7 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -79,7 +79,7 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior) /* Baked IOR for GGX BRDF. */ const float specular = 1.0; const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; - /* Avoid harsh transition comming from ior == 1. */ + /* Avoid harsh transition coming from ior == 1. */ float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25))); float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r; /* Setting the BTDF to one is not really important since it is only used for multiscatter diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl index 39a7e8fb931..c09365cdcb4 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl @@ -2,7 +2,7 @@ /** * Gather pass: Convolve foreground and background parts in separate passes. * - * Using the min&max CoC tile buffer, we select the best apropriate method to blur the scene color. + * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene color. * A fast gather path is taken if there is not many CoC variation inside the tile. * * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl index 1b5b305dfc1..d21254003f9 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl @@ -140,7 +140,7 @@ void main() do_scatter *= dof_scatter_screen_border_rejection(outCoc, uv, halfres); /* Only scatter if neighborhood is different enough. */ do_scatter *= dof_scatter_neighborhood_rejection(outColor.rgb); - /* For debuging. */ + /* For debugging. */ do_scatter *= float(!no_scatter_pass); outScatterColor = mix(vec3(0.0), outColor.rgb, do_scatter); diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl index 7689e730bf3..7568d70bd14 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl @@ -134,7 +134,7 @@ void raytrace_resolve(ClosureInputGlossy cl_in, vec3 V, P, N; if (planar_index != -1) { PlanarData pd = planars_data[planar_index]; - /* Evaluate everything in refected space. */ + /* Evaluate everything in reflected space. */ P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq); V = reflect(cl_common.V, pd.pl_normal); N = reflect(cl_in.N, pd.pl_normal); diff --git a/source/blender/draw/engines/eevee/shaders/random_lib.glsl b/source/blender/draw/engines/eevee/shaders/random_lib.glsl index 3a4ae257bbe..c2388f61346 100644 --- a/source/blender/draw/engines/eevee/shaders/random_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/random_lib.glsl @@ -1,6 +1,6 @@ /** - * Random numbers and low discrepency sequences utilities. + * Random numbers and low discrepancy sequences utilities. */ #pragma BLENDER_REQUIRE(common_math_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index 0efa7b80b0b..7d016d57c46 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -8,7 +8,7 @@ #if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) /* SSR will set these global variables itself. - * Also make false positive compiler warnings disapear by setting values. */ + * Also make false positive compiler warnings disappear by setting values. */ vec3 worldPosition = vec3(0); vec3 viewPosition = vec3(0); vec3 worldNormal = vec3(0); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index c48c3bffaef..777e48fde34 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -74,7 +74,7 @@ vec3 light_volume(LightData ld, vec4 l_vector) float d = l_vector.w; float d_sqr = sqr(d); float r_sqr = ld.l_volume_radius; - /* Using reformulation that has better numerical percision. */ + /* Using reformulation that has better numerical precision. */ power = 2.0 / (d_sqr + r_sqr + d * sqrt(d_sqr + r_sqr)); if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 674aca29662..328e60cf60b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -106,7 +106,7 @@ typedef struct gpLight { BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) BLI_STATIC_ASSERT_ALIGN(gpLight, 16) -/* *********** Draw Datas *********** */ +/* *********** Draw Data *********** */ typedef struct GPENCIL_MaterialPool { /* Linklist. */ struct GPENCIL_MaterialPool *next; diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh new file mode 100644 index 00000000000..d81b0971982 --- /dev/null +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -0,0 +1,153 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class DefaultDrawingMode : public AbstractDrawingMode { + private: + DRWPass *create_image_pass() const + { + /* Write depth is needed for background overlay rendering. Near depth is used for + * transparency checker and Far depth is used for indicating the image size. */ + DRWState state = static_cast<DRWState>(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA_PREMUL); + return DRW_pass_create("Image", state); + } + + void add_to_shgroup(AbstractSpaceAccessor *space, + DRWShadingGroup *grp, + const Image *image, + const ImBuf *image_buffer) const + { + float image_mat[4][4]; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ARegion *region = draw_ctx->region; + space->get_image_mat(image_buffer, region, image_mat); + + GPUBatch *geom = DRW_cache_quad_get(); + + const bool is_tiled_texture = image && image->source == IMA_SRC_TILED; + if (is_tiled_texture) { + const float translate_x = image_mat[3][0]; + const float translate_y = image_mat[3][1]; + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + const int tile_x = ((tile->tile_number - 1001) % 10); + const int tile_y = ((tile->tile_number - 1001) / 10); + image_mat[3][0] = (float)tile_x + translate_x; + image_mat[3][1] = (float)tile_y + translate_y; + DRW_shgroup_call_obmat(grp, geom, image_mat); + } + } + else { + DRW_shgroup_call_obmat(grp, geom, image_mat); + } + } + + public: + void cache_init(IMAGE_Data *vedata) const override + { + IMAGE_PassList *psl = vedata->psl; + + psl->image_pass = create_image_pass(); + } + + void cache_image(AbstractSpaceAccessor *space, + IMAGE_Data *vedata, + Image *image, + ImageUser *iuser, + ImBuf *image_buffer) const override + { + IMAGE_PassList *psl = vedata->psl; + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + GPUTexture *tex_tile_data = nullptr; + space->get_gpu_textures( + image, iuser, image_buffer, &pd->texture, &pd->owns_texture, &tex_tile_data); + if (pd->texture == nullptr) { + return; + } + const bool is_tiled_texture = tex_tile_data != nullptr; + + ShaderParameters sh_params; + sh_params.use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image, + image_buffer); + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + if (scene->camera && scene->camera->type == OB_CAMERA) { + Camera *camera = static_cast<Camera *>(scene->camera->data); + copy_v2_fl2(sh_params.far_near, camera->clip_end, camera->clip_start); + } + space->get_shader_parameters(sh_params, image_buffer, is_tiled_texture); + + GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture); + DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass); + if (is_tiled_texture) { + DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, GPU_SAMPLER_DEFAULT); + DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data); + } + else { + DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, GPU_SAMPLER_DEFAULT); + } + DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", sh_params.far_near); + DRW_shgroup_uniform_vec4_copy(shgrp, "color", ShaderParameters::color); + DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", sh_params.shuffle); + DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", sh_params.flags); + DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", sh_params.use_premul_alpha); + + add_to_shgroup(space, shgrp, image, image_buffer); + } + + void draw_finish(IMAGE_Data *vedata) const override + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + if (pd->texture && pd->owns_texture) { + GPU_texture_free(pd->texture); + pd->owns_texture = false; + } + pd->texture = nullptr; + } + + void draw_scene(IMAGE_Data *vedata) const override + { + IMAGE_PassList *psl = vedata->psl; + IMAGE_PrivateData *pd = vedata->stl->pd; + + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPU_framebuffer_bind(dfbl->default_fb); + static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0); + + DRW_view_set_active(pd->view); + DRW_draw_pass(psl->image_pass); + DRW_view_set_active(nullptr); + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c deleted file mode 100644 index 8b4acfbd5e3..00000000000 --- a/source/blender/draw/engines/image/image_engine.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2020, Blender Foundation. - */ - -/** \file - * \ingroup draw_editors - * - * Draw engine to draw the Image/UV editor - */ - -#include "DRW_render.h" - -#include "BKE_image.h" -#include "BKE_main.h" -#include "BKE_object.h" - -#include "DNA_camera_types.h" -#include "DNA_screen_types.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "ED_image.h" - -#include "GPU_batch.h" - -#include "image_engine.h" -#include "image_private.h" - -#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0) -#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1) -#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2) -#define IMAGE_DRAW_FLAG_DEPTH (1 << 3) -#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) -#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5) - -static void image_cache_image_add(DRWShadingGroup *grp, Image *image, ImBuf *ibuf) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - const ARegion *region = draw_ctx->region; - const char space_type = draw_ctx->space_data->spacetype; - - float zoom_x = 1.0f; - float zoom_y = 1.0f; - float translate_x = 0.0f; - float translate_y = 0.0f; - - /* User can freely move the backdrop in the space of the node editor */ - if (space_type == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)draw_ctx->space_data; - const float ibuf_width = ibuf->x; - const float ibuf_height = ibuf->y; - const float x = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof; - const float y = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof; - - zoom_x = ibuf_width * snode->zoom; - zoom_y = ibuf_height * snode->zoom; - translate_x = x; - translate_y = y; - } - - const bool is_tiled_texture = image && image->source == IMA_SRC_TILED; - float obmat[4][4]; - unit_m4(obmat); - - GPUBatch *geom = DRW_cache_quad_get(); - - obmat[0][0] = zoom_x; - obmat[1][1] = zoom_y; - obmat[3][1] = translate_y; - obmat[3][0] = translate_x; - - if (is_tiled_texture) { - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - const int tile_x = ((tile->tile_number - 1001) % 10); - const int tile_y = ((tile->tile_number - 1001) / 10); - obmat[3][1] = (float)tile_y + translate_y; - obmat[3][0] = (float)tile_x + translate_x; - DRW_shgroup_call_obmat(grp, geom, obmat); - } - } - else { - DRW_shgroup_call_obmat(grp, geom, obmat); - } -} - -static void space_image_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - if (image->rr != NULL) { - /* Update multi-index and pass for the current eye. */ - BKE_image_multilayer_index(image->rr, &sima->iuser); - } - else { - BKE_image_multiview_index(image, &sima->iuser); - } - - if (ibuf == NULL) { - return; - } - - if (ibuf->rect == NULL && ibuf->rect_float == NULL) { - /* This code-path is only supposed to happen when drawing a lazily-allocatable render result. - * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return NULL as - * an image buffer when it has no pixels. */ - - BLI_assert(image->type == IMA_TYPE_R_RESULT); - - float zero[4] = {0, 0, 0, 0}; - *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero); - *r_owns_texture = true; - return; - } - - const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); - if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) { - if (ibuf->zbuf) { - BLI_assert_msg(0, "Integer based depth buffers not supported"); - } - else if (ibuf->zbuf_float) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float); - *r_owns_texture = true; - } - else if (ibuf->rect_float && ibuf->channels == 1) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float); - *r_owns_texture = true; - } - } - else if (image->source == IMA_SRC_TILED) { - *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf); - *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL); - *r_owns_texture = false; - } - else { - *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); - *r_owns_texture = false; - } -} - -static void space_node_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); - *r_owns_texture = false; - *r_tex_tile_data = NULL; -} - -static void image_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - if (!image) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - - if (space_type == SPACE_IMAGE) { - space_image_gpu_texture_get( - image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data); - } - else if (space_type == SPACE_NODE) { - space_node_gpu_texture_get(image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data); - } -} - -static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser, ImBuf *ibuf) -{ - IMAGE_PassList *psl = vedata->psl; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - const Scene *scene = draw_ctx->scene; - - GPUTexture *tex_tile_data = NULL; - image_gpu_texture_get(image, iuser, ibuf, &pd->texture, &pd->owns_texture, &tex_tile_data); - - if (pd->texture) { - static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - static float shuffle[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - static float far_near[2] = {100.0f, 0.0f}; - - if (scene->camera && scene->camera->type == OB_CAMERA) { - far_near[1] = ((Camera *)scene->camera->data)->clip_start; - far_near[0] = ((Camera *)scene->camera->data)->clip_end; - } - - const bool use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image, ibuf); - const bool is_tiled_texture = tex_tile_data != NULL; - - int draw_flags = 0; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); - const bool do_repeat = (!is_tiled_texture) && ((sima->flag & SI_DRAW_TILE) != 0); - SET_FLAG_FROM_TEST(draw_flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT); - SET_FLAG_FROM_TEST(draw_flags, is_tiled_texture, IMAGE_DRAW_FLAG_USE_WORLD_POS); - if ((sima_flag & SI_USE_ALPHA) != 0) { - /* Show RGBA */ - draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - else if ((sima_flag & SI_SHOW_ALPHA) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f); - } - else if ((sima_flag & SI_SHOW_ZBUF) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); - } - else /* RGB */ { - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - } - } - if (space_type == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)draw_ctx->space_data; - if ((snode->flag & SNODE_USE_ALPHA) != 0) { - /* Show RGBA */ - draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f); - } - else if ((snode->flag & SNODE_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((snode->flag & SNODE_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); - } - else if ((snode->flag & SNODE_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); - } - else /* RGB */ { - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - } - } - - GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture); - DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass); - if (is_tiled_texture) { - DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, 0); - DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data); - } - else { - DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, 0); - } - DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", far_near); - DRW_shgroup_uniform_vec4_copy(shgrp, "color", color); - DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", shuffle); - DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", draw_flags); - DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", use_premul_alpha); - image_cache_image_add(shgrp, image, ibuf); - } -} - -/* -------------------------------------------------------------------- */ -/** \name Engine Callbacks - * \{ */ - -static void IMAGE_engine_init(void *ved) -{ - IMAGE_shader_library_ensure(); - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - if (!stl->pd) { - stl->pd = MEM_callocN(sizeof(IMAGE_PrivateData), __func__); - } - IMAGE_PrivateData *pd = stl->pd; - - pd->ibuf = NULL; - pd->lock = NULL; - pd->texture = NULL; -} - -static void IMAGE_cache_init(void *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - IMAGE_PassList *psl = vedata->psl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - { - /* Write depth is needed for background overlay rendering. Near depth is used for - * transparency checker and Far depth is used for indicating the image size. */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_BLEND_ALPHA_PREMUL; - psl->image_pass = DRW_pass_create("Image", state); - } - - const SpaceLink *space_link = draw_ctx->space_data; - const char space_type = space_link->spacetype; - pd->view = NULL; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - Image *image = ED_space_image(sima); - ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &pd->lock, 0); - image_cache_image(vedata, image, &sima->iuser, ibuf); - pd->image = image; - pd->ibuf = ibuf; - } - else if (space_type == SPACE_NODE) { - ARegion *region = draw_ctx->region; - Main *bmain = CTX_data_main(draw_ctx->evil_C); - Image *image = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &pd->lock); - { - /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */ - float winmat[4][4], viewmat[4][4]; - orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0); - unit_m4(winmat); - pd->view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - } - image_cache_image(vedata, image, NULL, ibuf); - pd->image = image; - pd->ibuf = ibuf; - } -} - -static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob)) -{ - /* Function intentional left empty. `cache_populate` is required to be implemented. */ -} - -static void image_draw_finish(IMAGE_Data *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - ED_space_image_release_buffer(sima, pd->ibuf, pd->lock); - } - else if (space_type == SPACE_NODE) { - BKE_image_release_ibuf(pd->image, pd->ibuf, pd->lock); - } - pd->image = NULL; - pd->ibuf = NULL; - - if (pd->texture && pd->owns_texture) { - GPU_texture_free(pd->texture); - pd->owns_texture = false; - } - pd->texture = NULL; -} - -static void IMAGE_draw_scene(void *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_PassList *psl = vedata->psl; - IMAGE_PrivateData *pd = vedata->stl->pd; - - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - GPU_framebuffer_bind(dfbl->default_fb); - static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0); - - DRW_view_set_active(pd->view); - DRW_draw_pass(psl->image_pass); - DRW_view_set_active(NULL); - image_draw_finish(vedata); -} - -static void IMAGE_engine_free(void) -{ - IMAGE_shader_free(); -} - -/** \} */ - -static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data); - -DrawEngineType draw_engine_image_type = { - NULL, /* next */ - NULL, /* prev */ - N_("UV/Image"), /* idname */ - &IMAGE_data_size, /* vedata_size */ - &IMAGE_engine_init, /* engine_init */ - &IMAGE_engine_free, /* engine_free */ - &IMAGE_cache_init, /* cache_init */ - &IMAGE_cache_populate, /* cache_populate */ - NULL, /* cache_finish */ - &IMAGE_draw_scene, /* draw_scene */ - NULL, /* view_update */ - NULL, /* id_update */ - NULL, /* render_to_image */ - NULL, /* store_metadata */ -}; diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc new file mode 100644 index 00000000000..491fbec978b --- /dev/null +++ b/source/blender/draw/engines/image/image_engine.cc @@ -0,0 +1,197 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Draw engine to draw the Image/UV editor + */ + +#include "DRW_render.h" + +#include <memory> +#include <optional> + +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_object.h" + +#include "DNA_camera_types.h" +#include "DNA_screen_types.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "ED_image.h" + +#include "GPU_batch.h" + +#include "image_drawing_mode.hh" +#include "image_engine.h" +#include "image_private.hh" +#include "image_space_image.hh" +#include "image_space_node.hh" + +namespace blender::draw::image_engine { + +static std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_context( + const DRWContextState *draw_ctx) +{ + const char space_type = draw_ctx->space_data->spacetype; + if (space_type == SPACE_IMAGE) { + return std::make_unique<SpaceImageAccessor>((SpaceImage *)draw_ctx->space_data); + } + if (space_type == SPACE_NODE) { + return std::make_unique<SpaceNodeAccessor>((SpaceNode *)draw_ctx->space_data); + } + BLI_assert_unreachable(); + return nullptr; +} + +class ImageEngine { + private: + const DRWContextState *draw_ctx; + IMAGE_Data *vedata; + std::unique_ptr<AbstractSpaceAccessor> space; + DefaultDrawingMode drawing_mode; + + public: + ImageEngine(const DRWContextState *draw_ctx, IMAGE_Data *vedata) + : draw_ctx(draw_ctx), vedata(vedata), space(space_accessor_from_context(draw_ctx)) + { + } + + virtual ~ImageEngine() = default; + + void cache_init() + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + drawing_mode.cache_init(vedata); + pd->view = nullptr; + if (space->has_view_override()) { + const ARegion *region = draw_ctx->region; + pd->view = space->create_view_override(region); + } + } + + void cache_populate() + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + Main *bmain = CTX_data_main(draw_ctx->evil_C); + pd->image = space->get_image(bmain); + if (pd->image == nullptr) { + /* Early exit, nothing to draw. */ + return; + } + pd->ibuf = space->acquire_image_buffer(pd->image, &pd->lock); + ImageUser *iuser = space->get_image_user(); + drawing_mode.cache_image(space.get(), vedata, pd->image, iuser, pd->ibuf); + } + + void draw_finish() + { + drawing_mode.draw_finish(vedata); + + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + space->release_buffer(pd->image, pd->ibuf, pd->lock); + pd->image = nullptr; + pd->ibuf = nullptr; + } + + void draw_scene() + { + drawing_mode.draw_scene(vedata); + } +}; + +/* -------------------------------------------------------------------- */ +/** \name Engine Callbacks + * \{ */ + +static void IMAGE_engine_init(void *ved) +{ + IMAGE_shader_library_ensure(); + IMAGE_Data *vedata = (IMAGE_Data *)ved; + IMAGE_StorageList *stl = vedata->stl; + if (!stl->pd) { + stl->pd = static_cast<IMAGE_PrivateData *>(MEM_callocN(sizeof(IMAGE_PrivateData), __func__)); + } + IMAGE_PrivateData *pd = stl->pd; + + pd->ibuf = nullptr; + pd->lock = nullptr; + pd->texture = nullptr; +} + +static void IMAGE_cache_init(void *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata)); + image_engine.cache_init(); + image_engine.cache_populate(); +} + +static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob)) +{ + /* Function intentional left empty. `cache_populate` is required to be implemented. */ +} + +static void IMAGE_draw_scene(void *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata)); + image_engine.draw_scene(); + image_engine.draw_finish(); +} + +static void IMAGE_engine_free() +{ + IMAGE_shader_free(); +} + +/** \} */ + +static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data); + +} // namespace blender::draw::image_engine + +extern "C" { + +using namespace blender::draw::image_engine; + +DrawEngineType draw_engine_image_type = { + nullptr, /* next */ + nullptr, /* prev */ + N_("UV/Image"), /* idname */ + &IMAGE_data_size, /* vedata_size */ + &IMAGE_engine_init, /* engine_init */ + &IMAGE_engine_free, /* engine_free */ + &IMAGE_cache_init, /* cache_init */ + &IMAGE_cache_populate, /* cache_populate */ + nullptr, /* cache_finish */ + &IMAGE_draw_scene, /* draw_scene */ + nullptr, /* view_update */ + nullptr, /* id_update */ + nullptr, /* render_to_image */ + nullptr, /* store_metadata */ +}; +} diff --git a/source/blender/draw/engines/image/image_engine.h b/source/blender/draw/engines/image/image_engine.h index 0098d863ef9..f7e2f53d41b 100644 --- a/source/blender/draw/engines/image/image_engine.h +++ b/source/blender/draw/engines/image/image_engine.h @@ -17,9 +17,17 @@ */ /** \file - * \ingroup draw_editors + * \ingroup draw_engine */ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + extern DrawEngineType draw_engine_image_type; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/image/image_private.hh b/source/blender/draw/engines/image/image_private.hh new file mode 100644 index 00000000000..a62cd882e40 --- /dev/null +++ b/source/blender/draw/engines/image/image_private.hh @@ -0,0 +1,196 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include <optional> + +/* Forward declarations */ +extern "C" { +struct GPUTexture; +struct ImBuf; +struct Image; +} + +/* *********** LISTS *********** */ + +namespace blender::draw::image_engine { + +/* GPUViewport.storage + * Is freed every time the viewport engine changes. */ +struct IMAGE_PassList { + DRWPass *image_pass; +}; + +struct IMAGE_PrivateData { + void *lock; + struct ImBuf *ibuf; + struct Image *image; + struct DRWView *view; + + struct GPUTexture *texture; + bool owns_texture; +}; + +struct IMAGE_StorageList { + IMAGE_PrivateData *pd; +}; + +struct IMAGE_Data { + void *engine_type; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; + IMAGE_PassList *psl; + IMAGE_StorageList *stl; +}; + +/* Shader parameters. */ +#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0) +#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1) +#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2) +#define IMAGE_DRAW_FLAG_DEPTH (1 << 3) +#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) +#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5) + +struct ShaderParameters { + constexpr static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + int flags = 0; + float shuffle[4]; + float far_near[2]; + bool use_premul_alpha = false; + + ShaderParameters() + { + copy_v4_fl(shuffle, 1.0f); + copy_v2_fl2(far_near, 100.0f, 0.0f); + } +}; + +/** + * Space accessor. + * + * Image engine is used to draw the images inside multiple spaces \see SpaceLink. + * The AbstractSpaceAccessor is an interface to communicate with a space. + */ +class AbstractSpaceAccessor { + public: + virtual ~AbstractSpaceAccessor() = default; + + /** + * Return the active image of the space. + * + * The returned image will be drawn in the space. + * + * The return value is optional. + */ + virtual Image *get_image(Main *bmain) = 0; + + /** + * Return the #ImageUser of the space. + * + * The return value is optional. + */ + virtual ImageUser *get_image_user() = 0; + + /** + * Acquire the image buffer of the image. + * + * \param image: Image to get the buffer from. Image is the same as returned from the #get_image + * member. + * \param lock: pointer to a lock object. + * \return Image buffer of the given image. + */ + virtual ImBuf *acquire_image_buffer(Image *image, void **lock) = 0; + + /** + * Release a previous locked image from #acquire_image_buffer. + */ + virtual void release_buffer(Image *image, ImBuf *image_buffer, void *lock) = 0; + + /** + * Update the r_shader_parameters with space specific settings. + * + * Only update the #ShaderParameters.flags and #ShaderParameters.shuffle. Other parameters + * are updated inside the image engine. + */ + virtual void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *image_buffer, + bool is_tiled) = 0; + + /** + * Retrieve the gpu textures to draw. + */ + virtual void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *image_buffer, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) = 0; + + /** + * Does this space override the view. + * When so this member should return true and the create_view_override must return the view to + * use during drawing. + */ + virtual bool has_view_override() const = 0; + + /** + * Override the view for drawing. + * Should match #has_view_override. + */ + virtual DRWView *create_view_override(const ARegion *UNUSED(region)) = 0; + + /** + * Initialize the matrix that will be used to draw the image. The matrix will be send as object + * matrix to the drawing pipeline. + */ + virtual void get_image_mat(const ImBuf *image_buffer, + const ARegion *region, + float r_mat[4][4]) const = 0; +}; // namespace blender::draw::image_engine + +/** + * Abstract class for a drawing mode of the image engine. + * + * The drawing mode decides how to draw the image on the screen. Each way how to draw would have + * its own subclass. For now there is only a single drawing mode. #DefaultDrawingMode. + **/ +class AbstractDrawingMode { + public: + virtual ~AbstractDrawingMode() = default; + virtual void cache_init(IMAGE_Data *vedata) const = 0; + virtual void cache_image(AbstractSpaceAccessor *space, + IMAGE_Data *vedata, + Image *image, + ImageUser *iuser, + ImBuf *image_buffer) const = 0; + virtual void draw_scene(IMAGE_Data *vedata) const = 0; + virtual void draw_finish(IMAGE_Data *vedata) const = 0; +}; + +/* image_shader.c */ +GPUShader *IMAGE_shader_image_get(bool is_tiled_image); +void IMAGE_shader_library_ensure(void); +void IMAGE_shader_free(void); + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_shader.c b/source/blender/draw/engines/image/image_shader.cc index 691c0d7029a..1c6abf36505 100644 --- a/source/blender/draw/engines/image/image_shader.c +++ b/source/blender/draw/engines/image/image_shader.cc @@ -27,27 +27,31 @@ #include "GPU_batch.h" #include "image_engine.h" -#include "image_private.h" +#include "image_private.hh" +extern "C" { extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_engine_image_frag_glsl[]; extern char datatoc_engine_image_vert_glsl[]; +} + +namespace blender::draw::image_engine { -typedef struct IMAGE_Shaders { +struct IMAGE_Shaders { GPUShader *image_sh[2]; -} IMAGE_Shaders; +}; static struct { IMAGE_Shaders shaders; DRWShaderLibrary *lib; -} e_data = {{{0}}}; /* Engine data */ +} e_data = {{{nullptr}}}; /* Engine data */ -void IMAGE_shader_library_ensure(void) +void IMAGE_shader_library_ensure() { - if (e_data.lib == NULL) { + if (e_data.lib == nullptr) { e_data.lib = DRW_shader_library_create(); /* NOTE: These need to be ordered by dependencies. */ DRW_SHADER_LIB_ADD(e_data.lib, common_colormanagement_lib); @@ -60,18 +64,18 @@ GPUShader *IMAGE_shader_image_get(bool is_tiled_image) { const int index = is_tiled_image ? 1 : 0; IMAGE_Shaders *sh_data = &e_data.shaders; - if (!sh_data->image_sh[index]) { + if (sh_data->image_sh[index] == nullptr) { sh_data->image_sh[index] = DRW_shader_create_with_shaderlib( datatoc_engine_image_vert_glsl, - NULL, + nullptr, datatoc_engine_image_frag_glsl, e_data.lib, - is_tiled_image ? "#define TILED_IMAGE\n" : NULL); + is_tiled_image ? "#define TILED_IMAGE\n" : nullptr); } return sh_data->image_sh[index]; } -void IMAGE_shader_free(void) +void IMAGE_shader_free() { GPUShader **sh_data_as_array = (GPUShader **)&e_data.shaders; for (int i = 0; i < (sizeof(IMAGE_Shaders) / sizeof(GPUShader *)); i++) { @@ -80,3 +84,5 @@ void IMAGE_shader_free(void) DRW_SHADER_LIB_FREE_SAFE(e_data.lib); } + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_space_image.hh b/source/blender/draw/engines/image/image_space_image.hh new file mode 100644 index 00000000000..7728a963254 --- /dev/null +++ b/source/blender/draw/engines/image/image_space_image.hh @@ -0,0 +1,182 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class SpaceImageAccessor : public AbstractSpaceAccessor { + SpaceImage *sima; + + public: + SpaceImageAccessor(SpaceImage *sima) : sima(sima) + { + } + + Image *get_image(Main *UNUSED(bmain)) override + { + return ED_space_image(sima); + } + + ImageUser *get_image_user() override + { + return &sima->iuser; + } + + ImBuf *acquire_image_buffer(Image *UNUSED(image), void **lock) override + { + return ED_space_image_acquire_buffer(sima, lock, 0); + } + + void release_buffer(Image *UNUSED(image), ImBuf *image_buffer, void *lock) override + { + ED_space_image_release_buffer(sima, image_buffer, lock); + } + + void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *image_buffer, + bool is_tiled) override + { + const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer); + const bool do_repeat = (!is_tiled) && ((sima->flag & SI_DRAW_TILE) != 0); + SET_FLAG_FROM_TEST(r_shader_parameters.flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT); + SET_FLAG_FROM_TEST(r_shader_parameters.flags, is_tiled, IMAGE_DRAW_FLAG_USE_WORLD_POS); + if ((sima_flag & SI_USE_ALPHA) != 0) { + /* Show RGBA */ + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + else if ((sima_flag & SI_SHOW_ALPHA) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f); + } + else if ((sima_flag & SI_SHOW_ZBUF) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_R) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_G) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_B) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f); + } + else /* RGB */ { + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + } + } + + bool has_view_override() const override + { + return false; + } + DRWView *create_view_override(const ARegion *UNUSED(region)) override + { + return nullptr; + } + + void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *image_buffer, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) override + { + if (image->rr != nullptr) { + /* Update multi-index and pass for the current eye. */ + BKE_image_multilayer_index(image->rr, iuser); + } + else { + BKE_image_multiview_index(image, iuser); + } + + if (image_buffer == nullptr) { + return; + } + + if (image_buffer->rect == nullptr && image_buffer->rect_float == nullptr) { + /* This code-path is only supposed to happen when drawing a lazily-allocatable render result. + * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return nullptr + * as an image buffer when it has no pixels. */ + + BLI_assert(image->type == IMA_TYPE_R_RESULT); + + float zero[4] = {0, 0, 0, 0}; + *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero); + *r_owns_texture = true; + return; + } + + const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer); + if (sima_flag & SI_SHOW_ZBUF && + (image_buffer->zbuf || image_buffer->zbuf_float || (image_buffer->channels == 1))) { + if (image_buffer->zbuf) { + BLI_assert_msg(0, "Integer based depth buffers not supported"); + } + else if (image_buffer->zbuf_float) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->zbuf_float); + *r_owns_texture = true; + } + else if (image_buffer->rect_float && image_buffer->channels == 1) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->rect_float); + *r_owns_texture = true; + } + } + else if (image->source == IMA_SRC_TILED) { + *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, image_buffer); + *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, nullptr); + *r_owns_texture = false; + } + else { + *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, image_buffer); + *r_owns_texture = false; + } + } + + void get_image_mat(const ImBuf *UNUSED(image_buffer), + const ARegion *UNUSED(region), + float r_mat[4][4]) const override + { + unit_m4(r_mat); + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_space_node.hh b/source/blender/draw/engines/image/image_space_node.hh new file mode 100644 index 00000000000..3ca18eec742 --- /dev/null +++ b/source/blender/draw/engines/image/image_space_node.hh @@ -0,0 +1,138 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class SpaceNodeAccessor : public AbstractSpaceAccessor { + SpaceNode *snode; + + public: + SpaceNodeAccessor(SpaceNode *snode) : snode(snode) + { + } + + Image *get_image(Main *bmain) override + { + return BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + } + + ImageUser *get_image_user() override + { + return nullptr; + } + + ImBuf *acquire_image_buffer(Image *image, void **lock) override + { + return BKE_image_acquire_ibuf(image, nullptr, lock); + } + + void release_buffer(Image *image, ImBuf *ibuf, void *lock) override + { + BKE_image_release_ibuf(image, ibuf, lock); + } + + bool has_view_override() const override + { + return true; + } + + DRWView *create_view_override(const ARegion *region) override + { + /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */ + float winmat[4][4], viewmat[4][4]; + orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0); + unit_m4(winmat); + return DRW_view_create(viewmat, winmat, nullptr, nullptr, nullptr); + } + + void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *ibuf, + bool UNUSED(is_tiled)) override + { + if ((snode->flag & SNODE_USE_ALPHA) != 0) { + /* Show RGBA */ + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f); + } + else if ((snode->flag & SNODE_SHOW_R) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((snode->flag & SNODE_SHOW_G) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f); + } + else if ((snode->flag & SNODE_SHOW_B) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f); + } + else /* RGB */ { + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + } + } + + void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *ibuf, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) override + { + *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); + *r_owns_texture = false; + *r_tex_tile_data = nullptr; + } + + void get_image_mat(const ImBuf *image_buffer, + const ARegion *region, + float r_mat[4][4]) const override + { + unit_m4(r_mat); + const float ibuf_width = image_buffer->x; + const float ibuf_height = image_buffer->y; + + r_mat[0][0] = ibuf_width * snode->zoom; + r_mat[1][1] = ibuf_height * snode->zoom; + r_mat[3][0] = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof; + r_mat[3][1] = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof; + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl index 92d5df1a13a..c4580e6ffc3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl @@ -95,7 +95,7 @@ void main() /** * ----------------- STEP 0.5 ------------------ - * Custom Coc aware downsampling. Quater res pass. + * Custom Coc aware downsampling. Quarter res pass. */ #ifdef DOWNSAMPLE diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 59ed5316c02..1c7e8bd8ad6 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1368,11 +1368,11 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) } /* update a viewport which belongs to a GPUOffscreen */ -void DRW_notify_view_update_offscreen(struct Depsgraph *depsgraph, - RenderEngineType *engine_type, - ARegion *region, - View3D *v3d, - GPUViewport *viewport) +static void DRW_notify_view_update_offscreen(struct Depsgraph *depsgraph, + RenderEngineType *engine_type, + ARegion *region, + View3D *v3d, + GPUViewport *viewport) { if (viewport && GPU_viewport_do_update(viewport)) { diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index a9810b4cc77..ef702821a59 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -13,15 +13,18 @@ #include "intern/draw_manager_testing.h" +#include "engines/basic/basic_private.h" #include "engines/eevee/eevee_private.h" #include "engines/gpencil/gpencil_engine.h" -#include "engines/image/image_private.h" +#include "engines/image/image_private.hh" #include "engines/overlay/overlay_private.h" #include "engines/workbench/workbench_private.h" #include "intern/draw_shader.h" namespace blender::draw { +using namespace blender::draw::image_engine; + static void test_workbench_glsl_shaders() { workbench_shader_library_ensure(); @@ -394,4 +397,17 @@ static void test_draw_glsl_shaders() } DRAW_TEST(draw_glsl_shaders) +static void test_basic_glsl_shaders() +{ + for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { + eGPUShaderConfig sh_cfg = static_cast<eGPUShaderConfig>(i); + BASIC_shaders_depth_sh_get(sh_cfg); + BASIC_shaders_pointcloud_depth_sh_get(sh_cfg); + BASIC_shaders_depth_conservative_sh_get(sh_cfg); + BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg); + } + BASIC_shaders_free(); +} +DRAW_TEST(basic_glsl_shaders) + } // namespace blender::draw diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index e5dc9a83ebb..9f2681fbf7a 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -199,7 +199,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa } /* set color for normal channels - * - use 3 shades of color group/standard color for 3 indention level + * - use 3 shades of color group/standard color for 3 indentation level * - only use group colors if allowed to, and if actually feasible */ if (showGroupColors && (grp) && (grp->customCol)) { diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 6fe32699907..05837ed17b9 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -145,6 +145,22 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) } } } + /* For node sockets, it is useful to include the node name as well (multiple similar nodes + * are not distinguishable otherwise). Unfortunately, the node label cannot be retrieved + * from the rna path, for this to work access to the underlying node is needed (but finding + * the node iterates all nodes & sockets which would result in bad performance in some + * circumstances). */ + if (RNA_struct_is_a(ptr.type, &RNA_NodeSocket)) { + char nodename[256]; + if (BLI_str_quoted_substr(fcu->rna_path, "nodes[", nodename, sizeof(nodename))) { + const char *structname_all = BLI_sprintfN("%s : %s", nodename, structname); + if (free_structname) { + MEM_freeN((void *)structname); + } + structname = structname_all; + free_structname = 1; + } + } } /* Property Name is straightforward */ diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 0d812198d04..335034fef6e 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -176,11 +176,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) copy_v3_v3(mpv->co, pchan_eval->pose_tail); } - /* result must be in worldspace */ + /* Result must be in world-space. */ mul_m4_v3(ob_eval->obmat, mpv->co); } else { - /* worldspace object location */ + /* World-space object location. */ copy_v3_v3(mpv->co, ob_eval->obmat[3]); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 32fd1c9ad41..b06e4b6a9e7 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -745,6 +745,10 @@ void ARMATURE_OT_separate(wmOperatorType *ot) #define ARM_PAR_CONNECT 1 #define ARM_PAR_OFFSET 2 +/* armature un-parenting options */ +#define ARM_PAR_CLEAR 1 +#define ARM_PAR_CLEAR_DISCONNECT 2 + /* check for null, before calling! */ static void bone_connect_to_existing_parent(EditBone *bone) { @@ -904,19 +908,29 @@ static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - bool all_childbones = false; + /* False when all selected bones are parented to the active bone. */ + bool enable_offset = false; + /* False when all selected bones are connected to the active bone. */ + bool enable_connect = false; { Object *ob = CTX_data_edit_object(C); bArmature *arm = ob->data; EditBone *actbone = arm->act_edbone; LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { - if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) { - if (ebone != actbone) { - if (ebone->parent != actbone) { - all_childbones = true; - break; - } - } + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone == actbone) { + continue; + } + + if (ebone->parent != actbone) { + enable_offset = true; + enable_connect = true; + break; + } + if (!(ebone->flag & BONE_CONNECTED)) { + enable_connect = true; } } } @@ -924,11 +938,14 @@ static int armature_parent_set_invoke(bContext *C, uiPopupMenu *pup = UI_popup_menu_begin( C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); - if (all_childbones) { - /* Object becomes parent, make the associated menus. */ - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); - } + + uiLayout *row_offset = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_offset, enable_offset); + uiItemEnumO(row_offset, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); + + uiLayout *row_connect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_connect, enable_connect); + uiItemEnumO(row_connect, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); UI_popup_menu_end(C, pup); @@ -955,8 +972,8 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot) } static const EnumPropertyItem prop_editarm_clear_parent_types[] = { - {1, "CLEAR", 0, "Clear Parent", ""}, - {2, "DISCONNECT", 0, "Disconnect Bone", ""}, + {ARM_PAR_CLEAR, "CLEAR", 0, "Clear Parent", ""}, + {ARM_PAR_CLEAR_DISCONNECT, "DISCONNECT", 0, "Disconnect Bone", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1012,6 +1029,51 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int armature_parent_clear_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) +{ + /* False when no selected bones are connected to the active bone. */ + bool enable_disconnect = false; + /* False when no selected bones are parented to the active bone. */ + bool enable_clear = false; + { + Object *ob = CTX_data_edit_object(C); + bArmature *arm = ob->data; + LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone->parent == NULL) { + continue; + } + enable_clear = true; + + if (ebone->flag & BONE_CONNECTED) { + enable_disconnect = true; + break; + } + } + } + + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Parent"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + uiLayout *row_clear = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_clear, enable_clear); + uiItemEnumO(row_clear, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR); + + uiLayout *row_disconnect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_disconnect, enable_disconnect); + uiItemEnumO( + row_disconnect, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR_DISCONNECT); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + void ARMATURE_OT_parent_clear(wmOperatorType *ot) { /* identifiers */ @@ -1021,7 +1083,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot) "Remove the parent-child relationship between selected bones and their parents"; /* api callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = armature_parent_clear_invoke; ot->exec = armature_parent_clear_exec; ot->poll = ED_operator_editarmature; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 279f79ac44b..70d6fa93104 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -797,13 +797,13 @@ static int pose_copy_exec(bContext *C, wmOperator *op) BLI_addtail(&temp_bmain->objects, &ob_copy); BLI_addtail(&temp_bmain->armatures, &arm_copy); /* begin copy buffer on a temp bmain. */ - BKE_copybuffer_begin(temp_bmain); + BKE_copybuffer_copy_begin(temp_bmain); /* Store the whole object to the copy buffer because pose can't be * existing on its own. */ - BKE_copybuffer_tag_ID(&ob_copy.id); + BKE_copybuffer_copy_tag_ID(&ob_copy.id); BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); - BKE_copybuffer_save(temp_bmain, str, op->reports); + BKE_copybuffer_copy_end(temp_bmain, str, op->reports); /* We clear the lists so no datablocks gets freed, * This is required because objects in temp bmain shares same pointers * as the real ones. diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh index dcc07f54e75..24def2fb4ab 100644 --- a/source/blender/editors/asset/ED_asset_list.hh +++ b/source/blender/editors/asset/ED_asset_list.hh @@ -35,4 +35,4 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C, /* Can return false to stop iterating. */ using AssetListIterFn = blender::FunctionRef<bool(AssetHandle)>; -void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn); +void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn); diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc index 8e1e5be2e47..9634665be7b 100644 --- a/source/blender/editors/asset/intern/asset_catalog.cc +++ b/source/blender/editors/asset/intern/asset_catalog.cc @@ -19,7 +19,6 @@ */ #include "BKE_asset_catalog.hh" -#include "BKE_asset_catalog_path.hh" #include "BKE_asset_library.hh" #include "BKE_main.h" diff --git a/source/blender/editors/asset/intern/asset_filter.cc b/source/blender/editors/asset/intern/asset_filter.cc index 329342a30cd..c22bbc923eb 100644 --- a/source/blender/editors/asset/intern/asset_filter.cc +++ b/source/blender/editors/asset/intern/asset_filter.cc @@ -22,7 +22,6 @@ #include "BLI_listbase.h" -#include "DNA_ID.h" #include "DNA_asset_types.h" #include "ED_asset_filter.h" diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc index 5c8d0b1349c..363bd9226da 100644 --- a/source/blender/editors/asset/intern/asset_handle.cc +++ b/source/blender/editors/asset/intern/asset_handle.cc @@ -26,7 +26,6 @@ #include <string> -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BLO_readfile.h" diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc index 5a83893f8e1..102b2a97859 100644 --- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -27,7 +27,6 @@ #include "BKE_preferences.h" -#include "DNA_asset_types.h" #include "DNA_userdef_types.h" #include "UI_resources.h" diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 4bc15e842fc..c1b1e33d428 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -32,7 +32,6 @@ #include "BLI_path_util.h" #include "BLI_utility_mixins.hh" -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BKE_preferences.h" @@ -40,7 +39,6 @@ #include "ED_fileselect.h" #include "WM_api.h" -#include "WM_types.h" /* XXX uses private header of file-space. */ #include "../space_file/filelist.h" @@ -458,9 +456,9 @@ bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *libr return AssetListStorage::lookup_list(*library_reference) != nullptr; } -void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn) +void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn) { - AssetList *list = AssetListStorage::lookup_list(*library_reference); + AssetList *list = AssetListStorage::lookup_list(library_reference); if (list) { list->iterate(fn); } diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc index a0a2c63b407..2e5bdb63359 100644 --- a/source/blender/editors/asset/intern/asset_mark_clear.cc +++ b/source/blender/editors/asset/intern/asset_mark_clear.cc @@ -20,9 +20,6 @@ * Functions for marking and clearing assets. */ -#include <memory> -#include <string> - #include "DNA_ID.h" #include "BKE_asset.h" @@ -32,8 +29,6 @@ #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BLO_readfile.h" - #include "UI_interface_icons.h" #include "RNA_access.h" diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index 1f5d3f5c101..3c4f6b8755f 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -18,8 +18,6 @@ * \ingroup edasset */ -#include "BKE_asset.h" -#include "BKE_asset_catalog.hh" #include "BKE_asset_library.hh" #include "BKE_bpath.h" #include "BKE_context.h" @@ -32,8 +30,6 @@ #include "BLI_fileops.h" #include "BLI_fnmatch.h" #include "BLI_path_util.h" -#include "BLI_string_ref.hh" -#include "BLI_vector.hh" #include "ED_asset.h" #include "ED_asset_catalog.hh" @@ -46,7 +42,6 @@ #include "RNA_define.h" #include "WM_api.h" -#include "WM_types.h" #include "DNA_space_types.h" diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index f664eab5cbb..f136c08f129 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -23,7 +23,6 @@ #include <new> -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BKE_report.h" diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 46bf1f6c9b5..3b05975d22d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4909,7 +4909,9 @@ bool ED_curve_editnurb_select_pick( /** \name Spin Operator * \{ */ -/* 'cent' is in object space and 'dvec' in worldspace. +/** + * \param axis: is in world-space. + * \param cent: is in object-space. */ bool ed_editnurb_spin( float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3]) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 26906b0ddcd..784f67ac4f1 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -102,7 +102,7 @@ struct CurveDrawData { /* offset projection by this value */ bool use_offset; - float offset[3]; /* worldspace */ + float offset[3]; /* world-space */ float surface_offset; bool use_surface_offset_absolute; } project; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 1b44cf88db1..6f18798bd2a 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -2155,8 +2155,8 @@ void FONT_OT_open(wmOperatorType *ot) FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, - FILE_DEFAULTDISPLAY, - FILE_SORT_DEFAULT); + FILE_IMGDISPLAY, + FILE_SORT_ALPHA); } /** \} */ diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index ba603cdd6ec..bf53241a947 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -123,6 +123,8 @@ typedef struct tGPsdata { ARegion *region; /** needed for GP_STROKE_2DSPACE. */ View2D *v2d; + /** For operations that require occlusion testing. */ + ViewDepths *depths; /** for using the camera rect within the 3d view. */ rctf *subrect; rctf subrect_data; @@ -972,12 +974,13 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points"); + const ViewDepths *depths = p->depths; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1086,7 +1089,10 @@ static bool annotation_stroke_eraser_is_occluded(tGPsdata *p, const int mval_i[2] = {x, y}; float mval_3d[3]; - if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) { + float p_depth; + if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) { + ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d); + const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d); const float depth_pt = ED_view3d_calc_depth_for_comparison(rv3d, &pt->x); @@ -1189,7 +1195,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p, /* Second Pass: Remove any points that are tagged */ if (do_cull) { BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } } @@ -1211,7 +1217,8 @@ static void annotation_stroke_doeraser(tGPsdata *p) if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + ED_view3d_depth_override( + p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths); } } @@ -1499,6 +1506,9 @@ static void annotation_session_cleanup(tGPsdata *p) static void annotation_session_free(tGPsdata *p) { + if (p->depths) { + ED_view3d_depths_free(p->depths); + } MEM_freeN(p); } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 406a7ac77fc..656fec565df 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1834,7 +1834,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Delete any selected point. */ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } BKE_reportf(op->reports, RPT_INFO, "Object created"); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index a77d3bee025..db2104dfdf9 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1321,78 +1321,102 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) } /* ********************** Merge Layer with the next layer **************************** */ +enum { + GP_LAYER_MERGE_ACTIVE = 0, + GP_LAYER_MERGE_ALL = 1, +}; -static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) +static void apply_layer_settings(bGPDlayer *gpl) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd); - bGPDlayer *gpl_dst = gpl_src->prev; + /* Apply layer attributes. */ + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->fill_opacity_fac *= gpl->opacity; + gps->vert_color_fill[3] *= gpl->opacity; + for (int p = 0; p < gps->totpoints; p++) { + bGPDspoint *pt = &gps->points[p]; + float factor = (((float)gps->thickness * pt->pressure) + (float)gpl->line_change) / + ((float)gps->thickness * pt->pressure); + pt->pressure *= factor; + pt->strength *= gpl->opacity; - if (ELEM(NULL, gpd, gpl_dst, gpl_src)) { - BKE_report(op->reports, RPT_ERROR, "No layers to merge"); - return OPERATOR_CANCELLED; + /* Layer transformation. */ + mul_v3_m4v3(&pt->x, gpl->layer_mat, &pt->x); + zero_v3(gpl->location); + zero_v3(gpl->rotation); + copy_v3_fl(gpl->scale, 1.0f); + } + } } - /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */ - GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64); - LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) { - BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); - } + gpl->line_change = 0; + gpl->opacity = 1.0f; + unit_m4(gpl->layer_mat); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); +} - /* Read all frames from merge layer and add any missing in destination layer, - * copying all previous strokes to keep the image equals. - * Need to do it in a separated loop to avoid strokes accumulation. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - /* Try to find frame in destination layer hash table. */ - bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); - if (!gpf_dst) { - gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); - /* Use same frame type. */ - gpf_dst->key_type = gpf_src->key_type; - BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); - } - } +static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); + bGPDlayer *gpl_dst = gpl_active->prev; + const int mode = RNA_enum_get(op->ptr, "mode"); - /* Read all frames from merge layer and add strokes. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - /* Try to find frame in destination layer hash table. */ - bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); - /* Apply layer transformation. */ - LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { - for (int p = 0; p < gps_src->totpoints; p++) { - bGPDspoint *pt = &gps_src->points[p]; - mul_v3_m4v3(&pt->x, gpl_src->layer_mat, &pt->x); - } + if (mode == GP_LAYER_MERGE_ACTIVE) { + if (ELEM(NULL, gpd, gpl_dst, gpl_active)) { + BKE_report(op->reports, RPT_ERROR, "No layers to merge"); + return OPERATOR_CANCELLED; } - - /* Add to tail all strokes. */ - if (gpf_dst) { - BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); + } + else { + if (ELEM(NULL, gpd, gpl_active)) { + BKE_report(op->reports, RPT_ERROR, "No layers to flatten"); + return OPERATOR_CANCELLED; } } - /* Add Masks to destination layer. */ - LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) { - /* Don't add merged layers or missing layer names. */ - if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) || - STREQ(mask->name, gpl_dst->info)) { - continue; + if (mode == GP_LAYER_MERGE_ACTIVE) { + /* Apply destination layer attributes. */ + apply_layer_settings(gpl_active); + ED_gpencil_layer_merge(gpd, gpl_active, gpl_dst, false); + } + else if (mode == GP_LAYER_MERGE_ALL) { + /* Apply layer attributes to all layers. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + apply_layer_settings(gpl); } - if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) { - bGPDlayer_Mask *mask_new = MEM_dupallocN(mask); - BLI_addtail(&gpl_dst->mask_layers, mask_new); - gpl_dst->act_mask++; + gpl_dst = gpl_active; + /* Merge layers on top of active layer. */ + if (gpd->layers.last != gpl_dst) { + LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) { + if (gpl == gpl_dst) { + break; + } + ED_gpencil_layer_merge(gpd, gpl, gpl->prev, false); + } } + /* Merge layers below active layer. */ + LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) { + if (gpl == gpl_dst) { + continue; + } + ED_gpencil_layer_merge(gpd, gpl, gpl_dst, true); + } + /* Set general layers settings to default values. */ + gpl_active->blend_mode = eGplBlendMode_Regular; + gpl_active->flag &= ~GP_LAYER_LOCKED; + gpl_active->flag &= ~GP_LAYER_HIDE; + gpl_active->flag |= GP_LAYER_USE_LIGHTS; + gpl_active->onion_flag |= GP_LAYER_ONIONSKIN; + } + else { + return OPERATOR_CANCELLED; } - /* Set destination layer as active. */ - BKE_gpencil_layer_active_set(gpd, gpl_dst); - - /* Now delete next layer */ - BKE_gpencil_layer_delete(gpd, gpl_src); - BLI_ghash_free(gh_frames_dst, NULL, NULL); - /* Reorder masking. */ - BKE_gpencil_layer_mask_sort(gpd, gpl_dst); + /* Clear any invalid mask. Some other layer could be using the merged layer. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + BKE_gpencil_layer_mask_cleanup(gpd, gpl); + } /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -1404,10 +1428,16 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) void GPENCIL_OT_layer_merge(wmOperatorType *ot) { + static const EnumPropertyItem merge_modes[] = { + {GP_LAYER_MERGE_ACTIVE, "ACTIVE", 0, "Active", "Combine active layer into the layer below"}, + {GP_LAYER_MERGE_ALL, "ALL", 0, "All", "Combine all layers into the active layer"}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ ot->name = "Merge Down"; ot->idname = "GPENCIL_OT_layer_merge"; - ot->description = "Merge the current layer with the layer below"; + ot->description = "Combine Layers"; /* callbacks */ ot->exec = gpencil_merge_layer_exec; @@ -1415,6 +1445,8 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", merge_modes, GP_LAYER_MERGE_ACTIVE, "Mode", ""); } /* ********************** Change Layer ***************************** */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f6012883e1f..3fc08096ab5 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2635,7 +2635,7 @@ static int gpencil_delete_selected_points(bContext *C) else { /* delete unwanted points by splitting stroke into several smaller ones */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } changed = true; @@ -4656,11 +4656,11 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0); + gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } /* selected strokes mode */ @@ -4839,11 +4839,11 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0); + gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } } @@ -5039,7 +5039,7 @@ static void gpencil_cutter_dissolve(bGPdata *gpd, } BKE_gpencil_stroke_delete_tagged_points( - gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1); + gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, flat_caps, 1); } } diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 1b69947b294..9860c75f290 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -127,6 +127,8 @@ typedef struct tGPDfill { struct bGPDstroke *gps_mouse; /** Pointer to report messages. */ struct ReportList *reports; + /** For operations that require occlusion testing. */ + struct ViewDepths *depths; /** flags */ short flag; /** avoid too fast events */ @@ -1374,7 +1376,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(tgpf->win, tgpf->region); ED_view3d_depth_override( - tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, &tgpf->depths); /* Since strokes are so fine, when using their depth we need a margin * otherwise they might get missed. */ @@ -1385,6 +1387,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) int interp_depth = 0; int found_depth = 0; + const ViewDepths *depths = tgpf->depths; tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points"); for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { @@ -1392,11 +1395,9 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) int mval_i[2]; round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(tgpf->region, mval_i, depth_margin, tgpf->depth_arr + i) == - 0) && - (i && - (ED_view3d_autodist_depth_seg( - tgpf->region, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1771,6 +1772,11 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op) ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d); } + /* Remove depth buffer in cache. */ + if (tgpf->depths) { + ED_view3d_depths_free(tgpf->depths); + } + /* finally, free memory used by temp data */ MEM_freeN(tgpf); } diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index b6730cb123b..3f3fd4fff39 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -155,6 +155,8 @@ typedef struct tGPDprimitive { struct Material *material; /** current brush */ struct Brush *brush; + /** For operations that require occlusion testing. */ + struct ViewDepths *depths; /** Settings to pass to gp_points_to_xy(). */ GP_SpaceConversion gsc; diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 259b2882589..925c2e1cd7f 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -182,7 +182,8 @@ static void gpencil_dissolve_points(bContext *C) } LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - BKE_gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + BKE_gpencil_stroke_delete_tagged_points( + gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } CTX_DATA_END; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 3e9f22f25d3..f0118988559 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -161,6 +161,8 @@ typedef struct tGPsdata { ARegion *region; /** needed for GP_STROKE_2DSPACE. */ View2D *v2d; + /** For operations that require occlusion testing. */ + ViewDepths *depths; /** for using the camera rect within the 3d view. */ rctf *subrect; rctf subrect_data; @@ -1090,14 +1092,16 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) int found_depth = 0; depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points"); + + const ViewDepths *depths = p->depths; int i; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1346,7 +1350,10 @@ static bool gpencil_stroke_eraser_is_occluded( /* calculate difference matrix if parent object */ BKE_gpencil_layer_transform_matrix_get(p->depsgraph, obact, gpl, diff_mat); - if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) { + float p_depth; + if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) { + ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d); + const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d); mul_v3_m4v3(fpt, diff_mat, &pt->x); @@ -1692,7 +1699,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } gpencil_update_cache(p->gpd); } @@ -1733,7 +1740,7 @@ static void gpencil_stroke_doeraser(tGPsdata *p) if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths); } /* loop over all layers too, since while it's easy to restrict editing to @@ -2087,6 +2094,9 @@ static void gpencil_session_free(tGPsdata *p) if (p->rng != NULL) { BLI_rng_free(p->rng); } + if (p->depths != NULL) { + ED_view3d_depths_free(p->depths); + } MEM_freeN(p); } @@ -2267,8 +2277,9 @@ static void gpencil_paint_initstroke(tGPsdata *p, static void gpencil_paint_strokeend(tGPsdata *p) { ToolSettings *ts = p->scene->toolsettings; - /* for surface sketching, need to set the right OpenGL context stuff so that - * the conversions will project the values correctly... + const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0; + /* for surface sketching, need to set the right OpenGL context stuff so + * that the conversions will project the values correctly... */ if (gpencil_project_check(p)) { View3D *v3d = p->area->spacedata.first; @@ -2282,11 +2293,11 @@ static void gpencil_paint_strokeend(tGPsdata *p) (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? V3D_DEPTH_GPENCIL_ONLY : V3D_DEPTH_NO_GPENCIL, - NULL); + is_eraser ? NULL : &p->depths); } /* check if doing eraser or not */ - if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { + if (!is_eraser) { /* transfer stroke to frame */ gpencil_stroke_newfrombuffer(p); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index f8cfc130e35..7382aca9a87 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -795,15 +795,16 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? V3D_DEPTH_GPENCIL_ONLY : V3D_DEPTH_NO_GPENCIL, - NULL); + &tgpi->depths); depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points"); + const ViewDepths *depths = tgpi->depths; tGPspoint *ptc = &points2D[0]; for (int i = 0; i < gps->totpoints; i++, ptc++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(tgpi->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - tgpi->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1154,6 +1155,11 @@ static void gpencil_primitive_exit(bContext *C, wmOperator *op) BLI_rng_free(tgpi->rng); } + /* Remove depth buffer in cache. */ + if (tgpi->depths) { + ED_view3d_depths_free(tgpi->depths); + } + MEM_freeN(tgpi); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index d3640c6eebd..86df452f49a 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -979,7 +979,7 @@ bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc, * to 3D coordinates. * * \param point2D: The screen-space 2D point data to convert. - * \param depth: Depth array (via #ED_view3d_autodist_depth()). + * \param depth: Depth array (via #ED_view3d_depth_read_cached()). * \param r_out: The resulting 2D point data. */ void gpencil_stroke_convertcoords_tpoint(Scene *scene, @@ -3372,7 +3372,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim( } /* Remove tagged points to trim stroke. */ gps_final = BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, 0); + gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0); } /* Join both strokes. */ @@ -3415,3 +3415,71 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold) BKE_gpencil_stroke_close(gps); } } + +/* Merge two layers. */ +void ED_gpencil_layer_merge(bGPdata *gpd, + bGPDlayer *gpl_src, + bGPDlayer *gpl_dst, + const bool reverse) +{ + /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */ + GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64); + LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) { + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); + } + + /* Read all frames from merge layer and add any missing in destination layer, + * copying all previous strokes to keep the image equals. + * Need to do it in a separated loop to avoid strokes accumulation. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + if (!gpf_dst) { + gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); + /* Use same frame type. */ + gpf_dst->key_type = gpf_src->key_type; + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); + } + } + + /* Read all frames from merge layer and add strokes. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + /* Add to tail all strokes. */ + if (gpf_dst) { + if (reverse) { + BLI_movelisttolist_reverse(&gpf_dst->strokes, &gpf_src->strokes); + } + else { + BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); + } + } + } + + /* Add Masks to destination layer. */ + LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) { + /* Don't add merged layers or missing layer names. */ + if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) || + STREQ(mask->name, gpl_dst->info)) { + continue; + } + if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) { + bGPDlayer_Mask *mask_new = MEM_dupallocN(mask); + BLI_addtail(&gpl_dst->mask_layers, mask_new); + gpl_dst->act_mask++; + } + } + + /* Set destination layer as active. */ + BKE_gpencil_layer_active_set(gpd, gpl_dst); + + /* Now delete merged layer. */ + BKE_gpencil_layer_delete(gpd, gpl_src); + BLI_ghash_free(gh_frames_dst, NULL, NULL); + + /* Reorder masking. */ + if (gpl_dst->mask_layers.first) { + BKE_gpencil_layer_mask_sort(gpd, gpl_dst); + } +} diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 5c3a7cf9e6f..891bd3ca5ec 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -54,7 +54,7 @@ static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1142,7 +1142,7 @@ void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot) static EnumPropertyItem mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Reset Vertex Color to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 21d8a28e2c9..4fa78eddec4 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -65,7 +65,7 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float *angle); bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]); bool ED_space_clip_color_sample(struct SpaceClip *sc, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index c760b661373..1cf15ce3a48 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -205,6 +205,11 @@ void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode) bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl); void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl); +void ED_gpencil_layer_merge(struct bGPdata *gpd, + struct bGPDlayer *gpl_src, + struct bGPDlayer *gpl_dst, + const bool reverse); + void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type); void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ef3ff7874df..eee119c0712 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -31,6 +31,8 @@ #include "DNA_object_enums.h" +#include "WM_types.h" + #include "BLI_compiler_attrs.h" #ifdef __cplusplus @@ -380,7 +382,7 @@ struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C); struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(struct ListBase *lb, const struct wmOperatorType *ot, struct IDProperty *prop, - short opcontext); + wmOperatorCallContext opcontext); struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(struct ListBase *lb, const struct MenuType *mt); struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(struct ListBase *lb, @@ -392,7 +394,7 @@ void ED_screen_user_menu_item_add_operator(struct ListBase *lb, const char *ui_name, const struct wmOperatorType *ot, const struct IDProperty *prop, - short opcontext); + wmOperatorCallContext opcontext); void ED_screen_user_menu_item_add_menu(struct ListBase *lb, const char *ui_name, const struct MenuType *mt); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8e19628ec87..008ad5b3203 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -588,8 +588,6 @@ float ED_view3d_radius_to_dist(const struct View3D *v3d, const bool use_aspect, const float radius); -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned int pos); - /* Back-buffer select and draw support. */ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist); @@ -609,12 +607,8 @@ bool ED_view3d_autodist_simple(struct ARegion *region, float mouse_worldloc[3], int margin, const float *force_depth); -bool ED_view3d_autodist_depth(struct ARegion *region, const int mval[2], int margin, float *depth); -bool ED_view3d_autodist_depth_seg(struct ARegion *region, - const int mval_sta[2], - const int mval_end[2], - int margin, - float *depth); +bool ED_view3d_depth_read_cached_seg( + const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth); /* select */ #define MAXPICKELEMS 2500 diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 1ed10f37de3..d5d45068828 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -27,6 +27,7 @@ #include "BLI_sys_types.h" /* size_t */ #include "BLI_utildefines.h" #include "UI_interface_icons.h" +#include "WM_types.h" #ifdef __cplusplus extern "C" { @@ -244,10 +245,10 @@ enum { }; /* Default font size for normal text. */ -#define UI_DEFAULT_TEXT_POINTS 11 +#define UI_DEFAULT_TEXT_POINTS 11.0f /* Larger size used for title text. */ -#define UI_DEFAULT_TITLE_POINTS 11 +#define UI_DEFAULT_TITLE_POINTS 11.0f #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 @@ -399,9 +400,8 @@ typedef enum { /** Resize handle (resize uilist). */ UI_BTYPE_GRIP = 57 << 9, UI_BTYPE_DECORATOR = 58 << 9, - UI_BTYPE_DATASETROW = 59 << 9, /* An item in a tree view. Parent items may be collapsible. */ - UI_BTYPE_TREEROW = 60 << 9, + UI_BTYPE_TREEROW = 59 << 9, } eButType; #define BUTTYPE (63 << 9) @@ -691,7 +691,7 @@ void UI_popup_block_ex(struct bContext *C, void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, - int opcontext); + wmOperatorCallContext opcontext); #endif void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block); @@ -731,8 +731,8 @@ bool UI_block_is_search_only(const uiBlock *block); void UI_block_set_search_only(uiBlock *block, bool search_only); void UI_block_free(const struct bContext *C, uiBlock *block); -void UI_blocklist_free(const struct bContext *C, struct ListBase *lb); -void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb); +void UI_blocklist_free(const struct bContext *C, struct ARegion *region); +void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region); void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen); void UI_block_region_set(uiBlock *block, struct ARegion *region); @@ -1003,7 +1003,7 @@ uiBut *uiDefButR_prop(uiBlock *block, uiBut *uiDefButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -1013,7 +1013,7 @@ uiBut *uiDefButO(uiBlock *block, uiBut *uiDefButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -1186,7 +1186,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block, uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -1196,7 +1196,7 @@ uiBut *uiDefIconButO(uiBlock *block, uiBut *uiDefIconButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -1382,7 +1382,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block, uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -1393,7 +1393,7 @@ uiBut *uiDefIconTextButO(uiBlock *block, uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -1675,11 +1675,7 @@ int UI_searchbox_size_x(void); int UI_search_items_find_index(uiSearchItems *items, const char *name); void UI_but_hint_drawstr_set(uiBut *but, const char *string); -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation); -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type); -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain); -uint8_t UI_but_datasetrow_component_get(uiBut *but); -uint8_t UI_but_datasetrow_domain_get(uiBut *but); + void UI_but_treerow_indentation_set(uiBut *but, int indentation); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); @@ -1724,7 +1720,7 @@ void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, const v struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, const char *opname, - short opcontext, + wmOperatorCallContext opcontext, int icon); struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon); struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon); @@ -1966,7 +1962,7 @@ void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout /* Only for convenience. */ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but); -void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext); +void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext); void uiLayoutSetActive(uiLayout *layout, bool active); void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default); void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init); @@ -2394,7 +2390,7 @@ void uiItemFullO_ptr(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr); void uiItemFullO(uiLayout *layout, @@ -2402,7 +2398,7 @@ void uiItemFullO(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr); void uiItemFullOMenuHold_ptr(uiLayout *layout, @@ -2410,7 +2406,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const char *menu_id, /* extra menu arg. */ struct PointerRNA *r_opptr); @@ -2490,14 +2486,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag); void uiItemsFullEnumO_items(uiLayout *layout, struct wmOperatorType *ot, struct PointerRNA ptr, struct PropertyRNA *prop, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const struct EnumPropertyItem *item_array, int totitem); diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 0d18eedeac9..8caf17741a7 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -217,15 +217,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer { friend class TreeViewLayoutBuilder; public: - using IsActiveFn = std::function<bool()>; - private: bool is_open_ = false; bool is_active_ = false; bool is_renaming_ = false; - IsActiveFn is_active_fn_; - protected: /** This label is used for identifying an item (together with its parent's labels). */ std::string label_{}; @@ -239,11 +235,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer { virtual void build_context_menu(bContext &C, uiLayout &column) const; virtual void on_activate(); - /** - * Set a custom callback to check if this item should be active. There's a version without - * arguments for checking if the item is currently in an active state. - */ - virtual void is_active(IsActiveFn is_active_fn); /** * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if @@ -329,6 +320,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer { */ void activate(); + /** + * If the result is not empty, it controls whether the item should be active or not, + * usually depending on the data that the view represents. + */ + virtual std::optional<bool> should_be_active() const; + + /** + * Return whether the item can be collapsed. Used to disable collapsing for items with children. + */ + virtual bool supports_collapsing() const; + private: static void rename_button_fn(bContext *, void *, char *); static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but); @@ -416,6 +418,7 @@ class AbstractTreeViewItemDropController { */ class BasicTreeViewItem : public AbstractTreeViewItem { public: + using IsActiveFn = std::function<bool()>; using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>; BIFIconID icon; @@ -423,7 +426,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem { void build_row(uiLayout &row) override; void add_label(uiLayout &layout, StringRefNull label_override = ""); - void on_activate(ActivateFn fn); + void set_on_activate_fn(ActivateFn fn); + /** + * Set a custom callback to check if this item should be active. + */ + void set_is_active_fn(IsActiveFn fn); protected: /** @@ -433,9 +440,12 @@ class BasicTreeViewItem : public AbstractTreeViewItem { */ ActivateFn activate_fn_; + IsActiveFn is_active_fn_; + private: static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2); + std::optional<bool> should_be_active() const override; void on_activate() override; }; diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 84172c7efce..bc3075f9de8 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -66,14 +66,14 @@ set(SRC interface_region_menu_popup.c interface_region_popover.c interface_region_popup.c - interface_region_search.c + interface_region_search.cc interface_region_tooltip.c interface_regions.c interface_style.c interface_template_asset_view.cc interface_template_list.cc interface_template_attribute_search.cc - interface_template_search_menu.c + interface_template_search_menu.cc interface_template_search_operator.c interface_templates.c interface_undo.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6ad0ef9de18..55fab04e9a4 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -37,6 +37,7 @@ #include "DNA_workspace_types.h" #include "BLI_alloca.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" @@ -1638,7 +1639,7 @@ typedef enum PredefinedExtraOpIconType { static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, wmOperatorType *optype, - short opcontext, + wmOperatorCallContext opcontext, int icon) { uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__); @@ -1678,7 +1679,7 @@ void ui_but_extra_operator_icons_free(uiBut *but) PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, const char *opname, - short opcontext, + wmOperatorCallContext opcontext, int icon) { wmOperatorType *optype = WM_operatortype_find(opname, false); @@ -1881,7 +1882,7 @@ bool ui_but_context_poll_operator_ex(bContext *C, bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but) { - const int opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT; + const wmOperatorCallContext opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT; return ui_but_context_poll_operator_ex( C, but, &(wmOperatorCallParams){.optype = ot, .opcontext = opcontext}); } @@ -1993,23 +1994,9 @@ void UI_block_end(const bContext *C, uiBlock *block) /* ************** BLOCK DRAWING FUNCTION ************* */ -void ui_fontscale(short *points, float aspect) +void ui_fontscale(float *points, float aspect) { - if (aspect < 0.9f || aspect > 1.1f) { - float pointsf = *points; - - /* For some reason scaling fonts goes too fast compared to widget size. */ - /* XXX(ton): not true anymore? */ - // aspect = sqrt(aspect); - pointsf /= aspect; - - if (aspect > 1.0f) { - *points = ceilf(pointsf); - } - else { - *points = floorf(pointsf); - } - } + *points /= aspect; } /* Project button or block (but==NULL) to pixels in region-space. */ @@ -3535,22 +3522,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb) } /* can be called with C==NULL */ -void UI_blocklist_free(const bContext *C, ListBase *lb) +void UI_blocklist_free(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; uiBlock *block; while ((block = BLI_pophead(lb))) { UI_block_free(C, block); } + if (region->runtime.block_name_map != NULL) { + BLI_ghash_free(region->runtime.block_name_map, NULL, NULL); + region->runtime.block_name_map = NULL; + } } -void UI_blocklist_free_inactive(const bContext *C, ListBase *lb) +void UI_blocklist_free_inactive(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; + LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) { if (!block->handle) { if (block->active) { block->active = false; } else { + if (region->runtime.block_name_map != NULL) { + uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name); + if (b == block) { + BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL); + } + } BLI_remlink(lb, block); UI_block_free(C, block); } @@ -3566,7 +3566,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* each listbase only has one block with this name, free block * if is already there so it can be rebuilt from scratch */ if (lb) { - oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name)); + if (region->runtime.block_name_map == NULL) { + region->runtime.block_name_map = BLI_ghash_str_new(__func__); + } + oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name); if (oldblock) { oldblock->active = false; @@ -3576,6 +3579,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* at the beginning of the list! for dynamical menus/blocks */ BLI_addhead(lb, block); + BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL); } block->oldblock = oldblock; @@ -3991,10 +3995,6 @@ static void ui_but_alloc_info(const eButType type, alloc_size = sizeof(uiButCurveProfile); alloc_str = "uiButCurveProfile"; break; - case UI_BTYPE_DATASETROW: - alloc_size = sizeof(uiButDatasetRow); - alloc_str = "uiButDatasetRow"; - break; case UI_BTYPE_TREEROW: alloc_size = sizeof(uiButTreeRow); alloc_str = "uiButTreeRow"; @@ -4197,7 +4197,6 @@ static uiBut *ui_def_but(uiBlock *block, UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW, UI_BTYPE_POPOVER)) { but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); @@ -4755,7 +4754,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5293,7 +5292,7 @@ uiBut *uiDefButR_prop(uiBlock *block, uiBut *uiDefButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5308,7 +5307,7 @@ uiBut *uiDefButO_ptr(uiBlock *block, uiBut *uiDefButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5676,7 +5675,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block, uiBut *uiDefIconButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -5691,7 +5690,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block, uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -6079,7 +6078,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block, uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -6096,7 +6095,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -6938,15 +6937,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, return but; } -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation) -{ - uiButDatasetRow *but_dataset = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset->indentation = indentation; - BLI_assert(indentation >= 0); -} - void UI_but_treerow_indentation_set(uiBut *but, int indentation) { uiButTreeRow *but_row = (uiButTreeRow *)but; @@ -6964,38 +6954,6 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->geometry_component_type = geometry_component_type; -} - -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->attribute_domain = attribute_domain; -} - -uint8_t UI_but_datasetrow_component_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->geometry_component_type; -} - -uint8_t UI_but_datasetrow_domain_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->attribute_domain; -} - void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) { but->flag |= UI_BUT_NODE_LINK; diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc index b0f8d186afa..3f5efd187d8 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -82,4 +82,4 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) } // namespace blender::ui -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index c3633e11f83..e45619d89e8 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -268,28 +268,28 @@ static bool eyedropper_cryptomatte_sample_fl( return false; } - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (!ar) { + ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (!region) { return false; } - int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin}; + int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; switch (sa->spacetype) { case SPACE_IMAGE: { SpaceImage *sima = sa->spacedata.first; - ED_space_image_get_position(sima, ar, mval, fpos); + ED_space_image_get_position(sima, region, mval, fpos); break; } case SPACE_NODE: { Main *bmain = CTX_data_main(C); SpaceNode *snode = sa->spacedata.first; - ED_space_node_get_position(bmain, snode, ar, mval, fpos); + ED_space_node_get_position(bmain, snode, region, mval, fpos); break; } case SPACE_CLIP: { SpaceClip *sc = sa->spacedata.first; - ED_space_clip_get_position(sc, ar, mval, fpos); + ED_space_clip_get_position(sc, region, mval, fpos); break; } default: { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6d69724efef..d18b3fdf505 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -492,7 +492,7 @@ typedef struct uiAfterFunc { wmOperator *popup_op; wmOperatorType *optype; - int opcontext; + wmOperatorCallContext opcontext; PointerRNA *opptr; PointerRNA rnapoin; @@ -775,7 +775,7 @@ static uiAfterFunc *ui_afterfunc_new(void) */ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot, PointerRNA **properties, - int opcontext, + wmOperatorCallContext opcontext, const uiBut *context_but) { uiAfterFunc *after = ui_afterfunc_new(); @@ -796,7 +796,7 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot, } } -void ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext) +void ui_handle_afterfunc_add_operator(wmOperatorType *ot, wmOperatorCallContext opcontext) { ui_handle_afterfunc_add_operator_ex(ot, NULL, opcontext, NULL); } @@ -2334,9 +2334,6 @@ static void ui_apply_but( case UI_BTYPE_LISTROW: ui_apply_but_LISTROW(C, block, but, data); break; - case UI_BTYPE_DATASETROW: - ui_apply_but_ROW(C, block, but, data); - break; case UI_BTYPE_TAB: ui_apply_but_TAB(C, but, data); break; @@ -8012,7 +8009,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_CHECKBOX: case UI_BTYPE_CHECKBOX_N: case UI_BTYPE_ROW: - case UI_BTYPE_DATASETROW: retval = ui_do_but_TOG(C, but, data, event); break; case UI_BTYPE_TREEROW: @@ -11344,8 +11340,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata)) return; } - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); bScreen *screen = CTX_wm_screen(C); if (screen == NULL) { return; diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index 3962ff6a702..577db6a0338 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -77,7 +77,7 @@ static void icon_draw_rect_input_text(const rctf *rect, const float color[4], const char *str, - int font_size) + float font_size) { BLF_batch_draw_flush(); const int font_id = BLF_default(); @@ -97,7 +97,7 @@ static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], BLF_batch_draw_flush(); const int font_id = blf_mono_font; BLF_color4fv(font_id, color); - BLF_size(font_id, 19 * U.pixelsize, U.dpi); + BLF_size(font_id, 19.0f * U.pixelsize, U.dpi); const float x = rect->xmin + (2.0f * U.pixelsize); const float y = rect->ymin + (1.0f * U.pixelsize); BLF_position(font_id, x, y, 0.0f); @@ -152,12 +152,12 @@ void icon_draw_rect_input(float x, if ((event_type >= EVT_AKEY) && (event_type <= EVT_ZKEY)) { const char str[2] = {'A' + (event_type - EVT_AKEY), '\0'}; - icon_draw_rect_input_text(&rect, color, str, 13); + icon_draw_rect_input_text(&rect, color, str, 13.0f); } else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F12KEY)) { char str[4]; SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY)); - icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8 : 10); + icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f); } else if (event_type == EVT_LEFTSHIFTKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}); @@ -167,7 +167,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Ctrl", 9); + icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f); } } else if (event_type == EVT_LEFTALTKEY) { @@ -175,7 +175,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Alt", 10); + icon_draw_rect_input_text(&rect, color, "Alt", 10.0f); } } else if (event_type == EVT_OSKEY) { @@ -186,20 +186,20 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "OS", 10); + icon_draw_rect_input_text(&rect, color, "OS", 10.0f); } } else if (event_type == EVT_DELKEY) { - icon_draw_rect_input_text(&rect, color, "Del", 9); + icon_draw_rect_input_text(&rect, color, "Del", 9.0f); } else if (event_type == EVT_TABKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0}); } else if (event_type == EVT_HOMEKEY) { - icon_draw_rect_input_text(&rect, color, "Home", 6); + icon_draw_rect_input_text(&rect, color, "Home", 6.0f); } else if (event_type == EVT_ENDKEY) { - icon_draw_rect_input_text(&rect, color, "End", 8); + icon_draw_rect_input_text(&rect, color, "End", 8.0f); } else if (event_type == EVT_RETKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0}); @@ -209,14 +209,14 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Esc", 8); + icon_draw_rect_input_text(&rect, color, "Esc", 8.0f); } } else if (event_type == EVT_PAGEUPKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8.0f); } else if (event_type == EVT_PAGEDOWNKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8.0f); } else if (event_type == EVT_LEFTARROWKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0}); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index f766bb1465f..e0686c1ff7a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -255,7 +255,7 @@ struct uiBut { /* Operator data */ struct wmOperatorType *optype; struct PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; /** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */ uchar menu_key; @@ -351,14 +351,6 @@ typedef struct uiButProgressbar { float progress; } uiButProgressbar; -/** Derived struct for #UI_BTYPE_DATASETROW. */ -typedef struct uiButDatasetRow { - uiBut but; - - uint8_t geometry_component_type; - uint8_t attribute_domain; - int indentation; -} uiButDatasetRow; /** Derived struct for #UI_BTYPE_TREEROW. */ typedef struct uiButTreeRow { @@ -609,7 +601,7 @@ typedef struct uiSafetyRct { /* interface.c */ -void ui_fontscale(short *points, float aspect); +void ui_fontscale(float *points, float aspect); extern void ui_block_to_region_fl(const struct ARegion *region, uiBlock *block, @@ -882,7 +874,7 @@ void ui_pie_menu_level_create(uiBlock *block, struct IDProperty *properties, const EnumPropertyItem *items, int totitem, - int context, + wmOperatorCallContext context, int flag); /* interface_region_popup.c */ @@ -960,7 +952,8 @@ const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack, int *r_cursor_index); /* interface_handlers.c */ -extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext); +extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, + wmOperatorCallContext opcontext); extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val); extern void ui_but_activate_event(struct bContext *C, struct ARegion *region, uiBut *but); extern void ui_but_activate_over(struct bContext *C, struct ARegion *region, uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 20e95ef4e9c..b792c59481c 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -82,7 +82,7 @@ typedef struct uiLayoutRoot { struct uiLayoutRoot *next, *prev; int type; - int opcontext; + wmOperatorCallContext opcontext; int emw, emh; int padding; @@ -1218,7 +1218,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1350,7 +1350,7 @@ void uiItemFullO_ptr(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1362,7 +1362,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const char *menu_id, PointerRNA *r_opptr) @@ -1376,7 +1376,7 @@ void uiItemFullO(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1474,7 +1474,7 @@ void uiItemsFullEnumO_items(uiLayout *layout, PointerRNA ptr, PropertyRNA *prop, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const EnumPropertyItem *item_array, int totitem) @@ -1623,7 +1623,7 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ @@ -3433,7 +3433,7 @@ void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc } typedef struct MenuItemLevel { - int opcontext; + wmOperatorCallContext opcontext; /* don't use pointers to the strings because python can dynamically * allocate strings and free before the menu draws, see T27304. */ char opname[OP_MAX_TYPENAME]; @@ -5672,7 +5672,7 @@ bool uiLayoutGetFixedSize(uiLayout *layout) return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0; } -void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext) +void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext) { layout->root->opcontext = opcontext; } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 3a8e06a3e49..8d47b8a1011 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1352,7 +1352,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; - short fstyle_points = fstyle->points; + float fstyle_points = fstyle->points; const float aspect = ((uiBlock *)region->uiblocks.first)->aspect; const float zoom = 1.0f / aspect; const int px = U.pixelsize; diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index bdf93d7c82e..a07222854d2 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -69,7 +69,6 @@ bool ui_but_is_toggle(const uiBut *but) UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_ROW, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW); } diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index 01562b25da1..0ffbdd6911c 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -330,7 +330,7 @@ typedef struct PieMenuLevelData { wmOperatorType *ot; const char *propname; IDProperty *properties; - int context, flag; + wmOperatorCallContext context, flag; } PieMenuLevelData; /** @@ -381,7 +381,7 @@ void ui_pie_menu_level_create(uiBlock *block, IDProperty *properties, const EnumPropertyItem *items, int totitem, - int context, + wmOperatorCallContext context, int flag) { const int totitem_parent = PIE_MAX_ITEMS - 1; diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index 4e20466326e..408953f8d0e 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -640,7 +640,7 @@ void UI_popup_block_ex(bContext *C, } #if 0 /* UNUSED */ -void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext) +void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, wmOperatorCallContext opcontext) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index f8f19c2e43d..5e7e0bfe9b5 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -90,7 +90,7 @@ struct uiPopover { #endif }; -static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext) +static void ui_popover_create_block(bContext *C, uiPopover *pup, wmOperatorCallContext opcontext) { BLI_assert(pup->ui_size_x != 0); diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 0e53100f91b..0f903bd4af9 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -743,7 +743,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, if (block_old) { block->oldblock = block_old; UI_block_update_from_old(C, block); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); } /* checks which buttons are visible, sets flags to prevent draw (do after region init) */ diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.cc index b8a19d06be1..eaf1ed3693b 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.cc @@ -23,9 +23,9 @@ * Search Box Region & Interaction */ -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> +#include <cstdarg> +#include <cstdlib> +#include <cstring> #include "DNA_ID.h" #include "MEM_guardedalloc.h" @@ -84,7 +84,7 @@ struct uiSearchItems { void *active; }; -typedef struct uiSearchboxData { +struct uiSearchboxData { rcti bbox; uiFontStyle fstyle; uiSearchItems items; @@ -102,7 +102,7 @@ typedef struct uiSearchboxData { * Used so we can show leading text to menu items less prominently (not related to 'use_sep'). */ const char *sep_string; -} uiSearchboxData; +}; #define SEARCH_ITEMS 10 @@ -166,9 +166,9 @@ bool UI_search_item_add(uiSearchItems *items, if (name_prefix_offset != 0) { /* Lazy initialize, as this isn't used often. */ - if (items->name_prefix_offsets == NULL) { - items->name_prefix_offsets = MEM_callocN( - items->maxitem * sizeof(*items->name_prefix_offsets), "search name prefix offsets"); + if (items->name_prefix_offsets == nullptr) { + items->name_prefix_offsets = (uint8_t *)MEM_callocN( + items->maxitem * sizeof(*items->name_prefix_offsets), __func__); } items->name_prefix_offsets[items->totitem] = name_prefix_offset; } @@ -198,7 +198,7 @@ int UI_searchbox_size_x(void) int UI_search_items_find_index(uiSearchItems *items, const char *name) { - if (items->name_prefix_offsets != NULL) { + if (items->name_prefix_offsets != nullptr) { for (int i = 0; i < items->totitem; i++) { if (STREQ(name, items->names[i] + items->name_prefix_offsets[i])) { return i; @@ -218,7 +218,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name) /* region is the search box itself */ static void ui_searchbox_select(bContext *C, ARegion *region, uiBut *but, int step) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* apply step */ data->active += step; @@ -285,14 +285,14 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr int ui_searchbox_find_index(ARegion *region, const char *name) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return UI_search_items_find_index(&data->items, name); } /* x and y in screen-coords. */ bool ui_searchbox_inside(ARegion *region, const int xy[2]) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin); } @@ -300,12 +300,12 @@ bool ui_searchbox_inside(ARegion *region, const int xy[2]) /* string validated to be of correct length (but->hardmax) */ bool ui_searchbox_apply(uiBut *but, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); - search_but->item_active = NULL; + search_but->item_active = nullptr; if (data->active != -1) { const char *name = data->items.names[data->active] + @@ -314,7 +314,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region) data->items.name_prefix_offsets[data->active] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; /* Search button with dynamic string properties may have their own method of applying * the search results, so only copy the result if there is a proper space for it. */ @@ -356,7 +356,7 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, } ARegion *searchbox_region = UI_region_searchbox_region_get(region); - uiSearchboxData *data = searchbox_region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(searchbox_region->regiondata); BLI_assert(data->items.pointers[data->active] == search_but->item_active); @@ -367,13 +367,13 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, C, region, &rect, search_but->arg, search_but->item_active); } } - return NULL; + return nullptr; } bool ui_searchbox_event( bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; int type = event->type, val = event->val; bool handled = false; @@ -481,7 +481,7 @@ static void ui_searchbox_update_fn(bContext *C, void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -499,7 +499,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re if (search_but->items_update_fn && search_but->item_active) { data->items.active = search_but->item_active; ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); - data->items.active = NULL; + data->items.active = nullptr; /* found active item, calculate real offset by centering it */ if (data->items.totitem) { @@ -538,7 +538,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re /* Never include the prefix in the button. */ (data->items.name_prefix_offsets ? data->items.name_prefix_offsets[a] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) { data->active = a; break; @@ -558,7 +558,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); int match = AUTOCOMPLETE_NO_MATCH; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -569,7 +569,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); match = UI_autocomplete_end(data->items.autocpl, str); - data->items.autocpl = NULL; + data->items.autocpl = nullptr; } return match; @@ -577,7 +577,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -630,7 +630,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; char *name = data->items.names[a]; int icon = data->items.icons[a]; - char *name_sep_test = NULL; + char *name_sep_test = nullptr; uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE; if (data->use_shortcut_sep) { @@ -652,15 +652,15 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* Simple menu item. */ - ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr); } else { /* Split menu item, faded text before the separator. */ - char *name_sep = NULL; + char *name_sep = nullptr; do { name_sep = name_sep_test; name_sep_test = strstr(name_sep + search_sep_len, data->sep_string); - } while (name_sep_test != NULL); + } while (name_sep_test != nullptr); name_sep += search_sep_len; const char name_sep_prev = *name_sep; @@ -683,7 +683,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* The previous menu item draws the active selection. */ - ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr); } } /* indicate more */ @@ -705,7 +705,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) static void ui_searchbox_region_free_fn(ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* free search data */ for (int a = 0; a < data->items.maxitem; a++) { @@ -716,12 +716,12 @@ static void ui_searchbox_region_free_fn(ARegion *region) MEM_freeN(data->items.icons); MEM_freeN(data->items.states); - if (data->items.name_prefix_offsets != NULL) { + if (data->items.name_prefix_offsets != nullptr) { MEM_freeN(data->items.name_prefix_offsets); } MEM_freeN(data); - region->regiondata = NULL; + region->regiondata = nullptr; } static ARegion *ui_searchbox_create_generic_ex(bContext *C, @@ -746,7 +746,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, region->type = &type; /* create searchbox data */ - uiSearchboxData *data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); + uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__); /* set font, get bb */ data->fstyle = style->widget; /* copy struct */ @@ -767,7 +767,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, data->prv_cols = but->a2; } - if (but->optype != NULL || use_shortcut_sep) { + if (but->optype != nullptr || use_shortcut_sep) { data->use_shortcut_sep = true; } data->sep_string = search_but->item_sep_string; @@ -881,13 +881,13 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, /* In case the button's string is dynamic, make sure there are buffers available. */ data->items.maxstrlen = but->hardmax == 0 ? UI_MAX_NAME_STR : but->hardmax; data->items.totitem = 0; - data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names"); - data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers"); - data->items.icons = MEM_callocN(data->items.maxitem * sizeof(int), "search icons"); - data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags"); - data->items.name_prefix_offsets = NULL; /* Lazy initialized as needed. */ + data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */ for (int i = 0; i < data->items.maxitem; i++) { - data->items.names[i] = MEM_callocN(data->items.maxstrlen + 1, "search pointers"); + data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__); } return region; @@ -924,7 +924,7 @@ static void str_tolower_titlecaps_ascii(char *str, const size_t len) static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -952,10 +952,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe { const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; - wmOperatorType *ot = data->items.pointers[a]; + wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]); char text_pre[128]; - char *text_pre_p = strstr(ot->idname, "_OT_"); - if (text_pre_p == NULL) { + const char *text_pre_p = strstr(ot->idname, "_OT_"); + if (text_pre_p == nullptr) { text_pre[0] = '\0'; } else { @@ -975,7 +975,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe data->items.icons[a], state, UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], @@ -983,7 +983,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe state, data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT : UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); } } /* indicate more */ @@ -1044,17 +1044,17 @@ void ui_but_search_refresh(uiButSearch *search_but) return; } - uiSearchItems *items = MEM_callocN(sizeof(uiSearchItems), "search items"); + uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__); /* setup search struct */ items->maxitem = 10; items->maxstrlen = 256; - items->names = MEM_callocN(items->maxitem * sizeof(void *), "search names"); + items->names = (char **)MEM_callocN(items->maxitem * sizeof(void *), __func__); for (int i = 0; i < items->maxitem; i++) { - items->names[i] = MEM_callocN(but->hardmax + 1, "search names"); + items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__); } - ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items); + ui_searchbox_update_fn((bContext *)but->block->evil_C, search_but, but->drawstr, items); if (!search_but->results_are_suggestions) { /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index eb25d896d26..0d8bdfc5817 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -960,7 +960,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* if operator poll check failed, it can give pretty precise info why */ if (optype) { - const int opcontext = extra_icon ? extra_icon->optype_params->opcontext : but->opcontext; + const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext : + but->opcontext; CTX_wm_operator_poll_msg_clear(C); ui_but_context_poll_operator_ex( C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext}); diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h index 0cb1fee9a92..ce938852520 100644 --- a/source/blender/editors/interface/interface_regions_intern.h +++ b/source/blender/editors/interface/interface_regions_intern.h @@ -22,9 +22,17 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* interface_region_menu_popup.c */ uint ui_popup_menu_hash(const char *str); /* interface_regions_intern.h */ ARegion *ui_region_temp_add(bScreen *screen); void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 92a9f14c77d..8bb1e477506 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -419,7 +419,7 @@ int UI_fontstyle_height_max(const uiFontStyle *fs) /* reading without uifont will create one */ void uiStyleInit(void) { - uiStyle *style = U.uistyles.first; + const uiStyle *style = U.uistyles.first; /* recover from uninitialized dpi */ if (U.dpi == 0) { @@ -483,16 +483,20 @@ void uiStyleInit(void) * Yes, this build the glyph cache and create * the texture. */ - BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 11.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 12.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 14.0f * U.pixelsize, U.dpi); } } if (style == NULL) { - ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); + style = ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); } + BLF_cache_flush_set_fn(UI_widgetbase_draw_cache_flush); + + BLF_default_size(style->widgetlabel.points); + /* XXX, this should be moved into a style, * but for now best only load the monospaced font once. */ BLI_assert(blf_mono_font == -1); @@ -506,7 +510,7 @@ void uiStyleInit(void) blf_mono_font = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font, 12.0f * U.pixelsize, 72); /* Set default flags based on UI preferences (not render fonts) */ { @@ -551,7 +555,7 @@ void uiStyleInit(void) blf_mono_font_render = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font_render, 12.0f * U.pixelsize, 72); } void UI_fontstyle_set(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 0ce30fdeb1a..0a3cff5fa98 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -178,7 +178,7 @@ static void asset_view_template_refresh_asset_collection( RNA_property_collection_clear(&assets_dataptr, assets_prop); - ED_assetlist_iterate(&asset_library_ref, [&](AssetHandle asset) { + ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) { if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) { /* Don't do anything else, but return true to continue iterating. */ return true; diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc index 5877b4fe6d7..fe7660e4221 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -21,8 +21,8 @@ * Accessed via the #WM_OT_search_menu operator. */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -85,16 +85,16 @@ struct MenuSearch_Context { }; struct MenuSearch_Parent { - struct MenuSearch_Parent *parent; + MenuSearch_Parent *parent; MenuType *parent_mt; const char *drawstr; /** Set while writing menu items only. */ - struct MenuSearch_Parent *temp_child; + MenuSearch_Parent *temp_child; }; struct MenuSearch_Item { - struct MenuSearch_Item *next, *prev; + MenuSearch_Item *next, *prev; const char *drawstr; const char *drawwstr_full; /** Support a single level sub-menu nesting (for operator buttons that expand). */ @@ -102,12 +102,12 @@ struct MenuSearch_Item { int icon; int state; - struct MenuSearch_Parent *menu_parent; + MenuSearch_Parent *menu_parent; MenuType *mt; - enum { - MENU_SEARCH_TYPE_OP = 1, - MENU_SEARCH_TYPE_RNA = 2, + enum Type { + Operator = 1, + RNA = 2, } type; union { @@ -115,7 +115,7 @@ struct MenuSearch_Item { struct { wmOperatorType *type; PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; bContextStore *context; } op; @@ -129,8 +129,8 @@ struct MenuSearch_Item { } rna; }; - /** Set when we need each menu item to be able to set its own context. may be NULL. */ - struct MenuSearch_Context *wm_context; + /** Set when we need each menu item to be able to set its own context. may be nullptr. */ + MenuSearch_Context *wm_context; }; struct MenuSearch_Data { @@ -148,15 +148,15 @@ struct MenuSearch_Data { static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v) { - const struct MenuSearch_Item *menu_item_a = menu_item_a_v; - const struct MenuSearch_Item *menu_item_b = menu_item_b_v; + const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v; + const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v; return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full); } static const char *strdup_memarena(MemArena *memarena, const char *str) { const uint str_size = strlen(str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); memcpy(str_dst, str, str_size); return str_dst; } @@ -164,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str) static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str) { const uint str_size = BLI_dynstr_get_len(dyn_str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); BLI_dynstr_get_cstring_ex(dyn_str, str_dst); return str_dst; } -static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, +static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data, MemArena *memarena, struct MenuType *mt, const char *drawstr_submenu, uiBut *but, - struct MenuSearch_Context *wm_context) + MenuSearch_Context *wm_context) { - struct MenuSearch_Item *item = NULL; + MenuSearch_Item *item = nullptr; /* Use override if the name is empty, this can happen with popovers. */ - const char *drawstr_override = NULL; + const char *drawstr_override = nullptr; const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0'); - if (but->optype != NULL) { + if (but->optype != nullptr) { if (drawstr_is_empty) { drawstr_override = WM_operatortype_name(but->optype, but->opptr); } - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = but->optype; item->op.opcontext = but->opcontext; item->op.context = but->context; item->op.opptr = but->opptr; - but->opptr = NULL; + but->opptr = nullptr; } - else if (but->rnaprop != NULL) { + else if (but->rnaprop != nullptr) { const int prop_type = RNA_property_type(but->rnaprop); if (drawstr_is_empty) { if (prop_type == PROP_ENUM) { const int value_enum = (int)but->hardmax; EnumPropertyItem enum_item; - if (RNA_property_enum_item_from_value_gettexted( - but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) { + if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C, + &but->rnapoin, + but->rnaprop, + value_enum, + &enum_item)) { drawstr_override = enum_item.name; } else { @@ -229,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d prop_type); } else { - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_RNA; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::RNA; item->rna.ptr = but->rnapoin; item->rna.prop = but->rnaprop; @@ -242,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d } } - if (item != NULL) { + if (item != nullptr) { /* Handle shared settings. */ - if (drawstr_override != NULL) { + if (drawstr_override != nullptr) { const char *drawstr_suffix = drawstr_sep ? drawstr_sep : ""; - char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix); - item->drawstr = strdup_memarena(memarena, drawstr_alloc); - MEM_freeN(drawstr_alloc); + std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix; + item->drawstr = strdup_memarena(memarena, drawstr.c_str()); } else { item->drawstr = strdup_memarena(memarena, but->drawstr); @@ -258,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)); item->mt = mt; - item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL; + item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr; item->wm_context = wm_context; @@ -272,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d /** * Populate a fake button from a menu item (use for context menu). */ -static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) +static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but) { bool changed = false; switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { but->optype = item->op.type; but->opcontext = item->op.opcontext; but->context = item->op.context; @@ -284,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) changed = true; break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { const int prop_type = RNA_property_type(item->rna.prop); but->rnapoin = item->rna.ptr; @@ -302,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) if (changed) { STRNCPY(but->drawstr, item->drawstr); char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; if (drawstr_sep) { *drawstr_sep = '\0'; } - but->icon = item->icon; + but->icon = (BIFIconID)item->icon; but->str = but->strdata; } @@ -327,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C, { wmWindowManager *wm = CTX_wm_manager(C); ListBase *handlers[] = { - region ? ®ion->handlers : NULL, - area ? &area->handlers : NULL, + region ? ®ion->handlers : nullptr, + area ? &area->handlers : nullptr, &win->handlers, }; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - if (handlers[handler_index] == NULL) { + if (handlers[handler_index] == nullptr) { continue; } LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) { @@ -345,7 +347,7 @@ static void menu_types_add_from_keymap_items(bContext *C, continue; } - if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) { + if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; wmEventHandler_KeymapResult km_result; WM_event_get_keymaps_from_handler(wm, win, handler, &km_result); @@ -382,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C, /** * Display all operators (last). Developer-only convenience feature. */ -static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data) +static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data) { /* Add to temporary list so we can sort them separately. */ - ListBase operator_items = {NULL, NULL}; + ListBase operator_items = {nullptr, nullptr}; MemArena *memarena = data->memarena; GHashIterator iter; for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { continue; @@ -400,13 +402,13 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d if (WM_operator_poll((bContext *)C, ot)) { const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); - struct MenuSearch_Item *item = NULL; - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + MenuSearch_Item *item = nullptr; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = ot; item->op.opcontext = WM_OP_INVOKE_DEFAULT; - item->op.context = NULL; + item->op.context = nullptr; char idname_as_py[OP_MAX_TYPENAME]; char uiname[256]; @@ -417,7 +419,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d item->drawwstr_full = strdup_memarena(memarena, uiname); item->drawstr = ot_ui_name; - item->wm_context = NULL; + item->wm_context = nullptr; BLI_addtail(&operator_items, item); } @@ -434,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d * - Look up predefined editor-menus. * - Look up key-map items which call menus. */ -static struct MenuSearch_Data *menu_items_from_ui_create( +static MenuSearch_Data *menu_items_from_ui_create( bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas) { MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -444,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( const uiStyle *style = UI_style_get_dpi(); /* Convert into non-ui structure. */ - struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__); + MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__); DynStr *dyn_str = BLI_dynstr_new_memarena(); /* Use a stack of menus to handle and discover new menus in passes. */ - LinkNode *menu_stack = NULL; + LinkNode *menu_stack = nullptr; /* Tag menu types not to add, either because they have already been added * or they have been blacklisted. @@ -466,7 +468,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { BLI_gset_add(menu_tagged, mt); } } @@ -483,7 +485,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter)); (BLI_ghashIterator_step(&iter))) { - MenuType *mt = BLI_ghashIterator_getValue(&iter); + MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter); if (BLI_str_endswith(mt->idname, "_context_menu")) { BLI_gset_add(menu_tagged, mt); } @@ -494,34 +496,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { - BLI_gset_remove(menu_tagged, mt, NULL); + if (mt != nullptr) { + BLI_gset_remove(menu_tagged, mt, nullptr); } } } /* Collect contexts, one for each 'ui_type'. */ - struct MenuSearch_Context *wm_contexts = NULL; + MenuSearch_Context *wm_contexts = nullptr; - const EnumPropertyItem *space_type_ui_items = NULL; + const EnumPropertyItem *space_type_ui_items = nullptr; int space_type_ui_items_len = 0; bool space_type_ui_items_free = false; /* Text used as prefix for top-bar menu items. */ - const char *global_menu_prefix = NULL; + const char *global_menu_prefix = nullptr; if (include_all_areas) { bScreen *screen = WM_window_get_active_screen(win); /* First create arrays for ui_type. */ - PropertyRNA *prop_ui_type = NULL; + PropertyRNA *prop_ui_type = nullptr; { /* This must be a valid pointer, with only it's type checked. */ - ScrArea area_dummy = { - /* Anything besides #SPACE_EMPTY is fine, - * as this value is only included in the enum when set. */ - .spacetype = SPACE_TOPBAR, - }; + ScrArea area_dummy = {nullptr}; + /* Anything besides #SPACE_EMPTY is fine, + * as this value is only included in the enum when set. */ + area_dummy.spacetype = SPACE_TOPBAR; PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr); prop_ui_type = RNA_struct_find_property(&ptr, "ui_type"); @@ -532,7 +533,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( &space_type_ui_items_len, &space_type_ui_items_free); - wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len); + wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc( + memarena, sizeof(*wm_contexts) * space_type_ui_items_len); for (int i = 0; i < space_type_ui_items_len; i++) { wm_contexts[i].space_type_ui_index = -1; } @@ -540,7 +542,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - if (region != NULL) { + if (region != nullptr) { PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr); const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type); @@ -573,16 +575,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len; space_type_ui_index += 1) { - ScrArea *area = NULL; - ARegion *region = NULL; - struct MenuSearch_Context *wm_context = NULL; + ScrArea *area = nullptr; + ARegion *region = nullptr; + MenuSearch_Context *wm_context = nullptr; if (include_all_areas) { if (space_type_ui_index == -1) { /* First run without any context, to populate the top-bar without. */ - wm_context = NULL; - area = NULL; - region = NULL; + wm_context = nullptr; + area = nullptr; + region = nullptr; } else { wm_context = &wm_contexts[space_type_ui_index]; @@ -607,7 +609,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * from the buttons, however this is quite involved and can be avoided as by convention * each space-type has a single root-menu that headers use. */ { - const char *idname_array[2] = {NULL}; + const char *idname_array[2] = {nullptr}; int idname_array_len = 0; /* Use negative for global (no area) context, populate the top-bar. */ @@ -623,8 +625,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( case space_type: \ break - if (area != NULL) { - SpaceLink *sl = area->spacedata.first; + if (area != nullptr) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; switch ((eSpace_Type)area->spacetype) { SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus"); SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus"); @@ -656,7 +658,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } for (int i = 0; i < idname_array_len; i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { /* Check if this exists because of 'include_all_areas'. */ if (BLI_gset_add(menu_tagged, mt)) { BLI_linklist_prepend(&menu_stack, mt); @@ -669,8 +671,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( bool has_keymap_menu_items = false; - while (menu_stack != NULL) { - MenuType *mt = BLI_linklist_pop(&menu_stack); + while (menu_stack != nullptr) { + MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack); if (!WM_menutype_poll(C, mt)) { continue; } @@ -687,7 +689,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( UI_block_end(C, block); LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - MenuType *mt_from_but = NULL; + MenuType *mt_from_but = nullptr; /* Support menu titles with dynamic from initial labels * (used by edit-mesh context menu). */ if (but->type == UI_BTYPE_LABEL) { @@ -698,13 +700,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create( but_test = but_test->prev; } - if (but_test == NULL) { + if (but_test == nullptr) { BLI_ghash_insert( menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr)); } } else if (menu_items_from_ui_create_item_from_button( - data, memarena, mt, NULL, but, wm_context)) { + data, memarena, mt, nullptr, but, wm_context)) { /* pass */ } else if ((mt_from_but = UI_but_menutype_get(but))) { @@ -714,8 +716,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) { - struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena, - sizeof(*menu_parent)); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc( + memarena, sizeof(*menu_parent)); /* Use brackets for menu key shortcuts, * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)". * This is needed so we don't right align sub-menu contents @@ -723,9 +725,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create( */ const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; bool drawstr_is_empty = false; - if (drawstr_sep != NULL) { + if (drawstr_sep != nullptr) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); /* Detect empty string, fallback to menu name. */ const char *drawstr = but->drawstr; @@ -760,7 +762,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } } - else if (but->menu_create_func != NULL) { + else if (but->menu_create_func != nullptr) { /* A non 'MenuType' menu button. */ /* Only expand one level deep, this is mainly for expanding operator menus. */ @@ -785,19 +787,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, sub_block); } - UI_block_free(NULL, sub_block); + UI_block_free(nullptr, sub_block); } } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, block); } - UI_block_free(NULL, block); + UI_block_free(nullptr, block); /* Add key-map items as a second pass, * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */ - if ((menu_stack == NULL) && (has_keymap_menu_items == false)) { + if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) { has_keymap_menu_items = true; menu_types_add_from_keymap_items( C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged); @@ -805,33 +809,34 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt); + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { + item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt); } GHASH_ITER (iter, menu_parent_map) { - struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter); - menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter); + menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, + menu_parent->parent_mt); } /* NOTE: currently this builds the full path for each menu item, * that could be moved into the parent menu. */ /* Set names as full paths. */ - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); if (include_all_areas) { BLI_dynstr_appendf(dyn_str, "%s: ", - (item->wm_context != NULL) ? + (item->wm_context != nullptr) ? space_type_ui_items[item->wm_context->space_type_ui_index].name : global_menu_prefix); } - if (item->menu_parent != NULL) { - struct MenuSearch_Parent *menu_parent = item->menu_parent; - menu_parent->temp_child = NULL; + if (item->menu_parent != nullptr) { + MenuSearch_Parent *menu_parent = item->menu_parent; + menu_parent->temp_child = nullptr; while (menu_parent && menu_parent->parent) { menu_parent->parent->temp_child = menu_parent; menu_parent = menu_parent->parent; @@ -843,14 +848,14 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } else { - const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt); - if (drawstr == NULL) { + const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt); + if (drawstr == nullptr) { drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label); } BLI_dynstr_append(dyn_str, drawstr); - wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt); - if (kmi != NULL) { + wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt); + if (kmi != nullptr) { char kmi_str[128]; WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str)); BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str); @@ -860,7 +865,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } /* Optional nested menu. */ - if (item->drawstr_submenu != NULL) { + if (item->drawstr_submenu != nullptr) { BLI_dynstr_append(dyn_str, item->drawstr_submenu); BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " "); } @@ -877,12 +882,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * NOTE: we might want to keep the in-menu order, for now sort all. */ BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full); - BLI_ghash_free(menu_parent_map, NULL, NULL); - BLI_ghash_free(menu_display_name_map, NULL, NULL); + BLI_ghash_free(menu_parent_map, nullptr, nullptr); + BLI_ghash_free(menu_display_name_map, nullptr, nullptr); - BLI_ghash_free(menu_to_kmi, NULL, NULL); + BLI_ghash_free(menu_to_kmi, nullptr, nullptr); - BLI_gset_free(menu_tagged, NULL); + BLI_gset_free(menu_tagged, nullptr); data->memarena = memarena; @@ -915,16 +920,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( static void menu_search_arg_free_fn(void *data_v) { - struct MenuSearch_Data *data = data_v; - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + MenuSearch_Data *data = (MenuSearch_Data *)data_v; + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { switch (item->type) { - case MENU_SEARCH_TYPE_OP: { - if (item->op.opptr != NULL) { + case MenuSearch_Item::Type::Operator: { + if (item->op.opptr != nullptr) { WM_operator_properties_free(item->op.opptr); MEM_freeN(item->op.opptr); } } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { break; } } @@ -937,8 +942,8 @@ static void menu_search_arg_free_fn(void *data_v) static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { - struct MenuSearch_Item *item = arg2; - if (item == NULL) { + MenuSearch_Item *item = (MenuSearch_Item *)arg2; + if (item == nullptr) { return; } if (item->state & UI_BUT_DISABLED) { @@ -948,20 +953,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { CTX_store_set(C, item->op.context); WM_operator_name_call_ptr_with_depends_on_cursor( C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { PointerRNA *ptr = &item->rna.ptr; PropertyRNA *prop = item->rna.prop; const int index = item->rna.index; @@ -992,7 +997,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) } } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1004,19 +1009,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C), uiSearchItems *items, const bool UNUSED(is_first)) { - struct MenuSearch_Data *data = arg; + MenuSearch_Data *data = (MenuSearch_Data *)arg; StringSearch *search = BLI_string_search_new(); - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_string_search_add(search, item->drawwstr_full, item); } - struct MenuSearch_Item **filtered_items; + MenuSearch_Item **filtered_items; const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items); for (int i = 0; i < filtered_amount; i++) { - struct MenuSearch_Item *item = filtered_items[i]; + MenuSearch_Item *item = filtered_items[i]; if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) { break; } @@ -1041,8 +1046,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, void *active, const struct wmEvent *event) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; bool has_menu = false; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); @@ -1055,7 +1060,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } @@ -1064,7 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, has_menu = true; } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1085,8 +1090,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void *arg, void *active) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); uiBut *but = &data->context_menu_data.but; @@ -1112,21 +1117,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } return region_tip; } - return NULL; + return nullptr; } /** \} */ @@ -1137,14 +1142,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void UI_but_func_menu_search(uiBut *but) { - bContext *C = but->block->evil_C; + bContext *C = (bContext *)but->block->evil_C; wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); /* When run from top-bar scan all areas in the current window. */ const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)); - struct MenuSearch_Data *data = menu_items_from_ui_create( - C, win, area, region, include_all_areas); + MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas); UI_but_func_search_set(but, /* Generic callback. */ ui_searchbox_create_menu, @@ -1153,7 +1157,7 @@ void UI_but_func_menu_search(uiBut *but) false, menu_search_arg_free_fn, menu_search_exec_fn, - NULL); + nullptr); UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu); UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index ac2f1bc090c..cbd57176a31 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1741,7 +1741,7 @@ static void template_search_add_button_name(uiBlock *block, static void template_search_add_button_operator(uiBlock *block, const char *const operator_name, - const int opcontext, + const wmOperatorCallContext opcontext, const int icon, const bool editable) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 7d1b7b80ccd..784f87d36c1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -114,7 +114,6 @@ typedef enum { UI_WTYPE_LISTITEM, UI_WTYPE_PROGRESSBAR, UI_WTYPE_NODESOCKET, - UI_WTYPE_DATASETROW, UI_WTYPE_TREEROW, } uiWidgetTypeEnum; @@ -3675,13 +3674,7 @@ static void widget_treerow( widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation); } -static void widget_datasetrow( - uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign) -{ - uiButDatasetRow *dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation); -} + static void widget_nodesocket( uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) @@ -4476,9 +4469,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) wt.custom = widget_progressbar; break; - case UI_WTYPE_DATASETROW: - wt.custom = widget_datasetrow; - break; case UI_WTYPE_TREEROW: wt.custom = widget_treerow; @@ -4811,11 +4801,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu fstyle = &style->widgetlabel; break; - case UI_BTYPE_DATASETROW: - wt = widget_type(UI_WTYPE_DATASETROW); - fstyle = &style->widgetlabel; - break; - case UI_BTYPE_TREEROW: wt = widget_type(UI_WTYPE_TREEROW); fstyle = &style->widgetlabel; diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index fcc878c440c..5fcf78dd565 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -111,7 +111,10 @@ void AbstractTreeView::update_from_old(uiBlock &new_block) uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block( &new_block, reinterpret_cast<uiTreeViewHandle *>(this)); - BLI_assert(old_view_handle); + if (old_view_handle == nullptr) { + is_reconstructed_ = true; + return; + } AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle); @@ -350,9 +353,14 @@ void AbstractTreeViewItem::on_activate() /* Do nothing by default. */ } -void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn) +std::optional<bool> AbstractTreeViewItem::should_be_active() const { - is_active_fn_ = is_active_fn; + return std::nullopt; +} + +bool AbstractTreeViewItem::supports_collapsing() const +{ + return true; } std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller() @@ -504,7 +512,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed) bool AbstractTreeViewItem::is_collapsible() const { - return !children_.is_empty(); + if (children_.is_empty()) { + return false; + } + return this->supports_collapsing(); } bool AbstractTreeViewItem::is_renaming() const @@ -546,7 +557,8 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button() void AbstractTreeViewItem::change_state_delayed() { - if (is_active_fn_()) { + const std::optional<bool> should_be_active = this->should_be_active(); + if (should_be_active.has_value() && *should_be_active) { activate(); } } @@ -670,11 +682,24 @@ void BasicTreeViewItem::on_activate() } } -void BasicTreeViewItem::on_activate(ActivateFn fn) +void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn) { activate_fn_ = fn; } +void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn) +{ + is_active_fn_ = is_active_fn; +} + +std::optional<bool> BasicTreeViewItem::should_be_active() const +{ + if (is_active_fn_) { + return is_active_fn_(); + } + return std::nullopt; +} + } // namespace blender::ui using namespace blender::ui; diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c index b49be324372..556fae70828 100644 --- a/source/blender/editors/io/io_gpencil_export.c +++ b/source/blender/editors/io/io_gpencil_export.c @@ -410,6 +410,7 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot) static const EnumPropertyItem gpencil_export_frame_items[] = { {GP_EXPORT_FRAME_ACTIVE, "ACTIVE", 0, "Active", "Include only active frame"}, {GP_EXPORT_FRAME_SELECTED, "SELECTED", 0, "Selected", "Include selected frames"}, + {GP_EXPORT_FRAME_SCENE, "SCENE", 0, "Scene", "Include all scene frames"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index e4cd48d95bb..912399c25b3 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -821,8 +821,8 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w float view_vec[3], cross[3]; /* convert the 2D normal into 3D */ - mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ - mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ + mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* World-space. */ + mul_mat3_m4_v3(vc.obedit->imat, nor); /* Local-space. */ /* correct the normal to be aligned on the view plane */ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 2146207308c..d7eaf58653f 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -80,7 +80,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; BMOperator spinop; - /* keep the values in worldspace since we're passing the obmat */ + /* Keep the values in world-space since we're passing the `obmat`. */ if (!EDBM_op_init(em, &spinop, op, diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index ee227c58fe7..18fe9cf7ad3 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec } } } + EDBM_select_flush(em); } EDBM_update(me, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index b712cfc24ed..76d48432834 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -236,7 +236,7 @@ typedef struct KnifeTool_OpData { GHash *facetrimap; KnifeBVH bvh; - const float (**cagecos)[3]; + float (**cagecos)[3]; BLI_mempool *kverts; BLI_mempool *kedges; @@ -491,7 +491,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) float numstr_size[2]; float posit[2]; const float bg_margin = 4.0f * U.dpi_fac; - const int font_size = 14.0f * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int distance_precision = 4; /* Calculate distance and convert to string. */ @@ -561,7 +561,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, const float arc_size = 64.0f * U.dpi_fac; const float bg_margin = 4.0f * U.dpi_fac; const float cap_size = 4.0f * U.dpi_fac; - const int font_size = 14 * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int angle_precision = 3; /* Angle arc in 3d space. */ @@ -3975,7 +3975,7 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_ BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT); - kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc( + kcd->cagecos[base_index] = BKE_editmesh_vert_coords_alloc( kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL); } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f81e2a65b9f..c77db10d74b 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2166,7 +2166,7 @@ static void copy_object_set_idnew(bContext *C) Main *bmain = CTX_data_main(C); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_libblock_relink_to_newid(&ob->id); + BKE_libblock_relink_to_newid(bmain, &ob->id, 0); } CTX_DATA_END; @@ -2399,7 +2399,7 @@ static void make_object_duplilist_real(bContext *C, Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob_dst->id); + BKE_libblock_relink_to_newid(bmain, &ob_dst->id, 0); DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); @@ -3395,8 +3395,11 @@ Base *ED_object_add_duplicate( ob = basen->object; - /* link own references to the newly duplicated data T26816. */ - BKE_libblock_relink_to_newid(&ob->id); + /* Link own references to the newly duplicated data T26816. + * Note that this function can be called from edit-mode code, in which case we may have to + * enforce remapping obdata (by default this is forbidden in edit mode). */ + const int remap_flag = BKE_object_is_in_editmode(ob) ? ID_REMAP_FORCE_OBDATA_IN_EDITMODE : 0; + BKE_libblock_relink_to_newid(bmain, &ob->id, remap_flag); /* DAG_relations_tag_update(bmain); */ /* caller must do */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index aa15ce36582..b51644eebf3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1685,18 +1685,20 @@ static bool single_data_needs_duplication(ID *id) return (id != NULL && (id->us > 1 || ID_IS_LINKED(id))); } -static void libblock_relink_collection(Collection *collection, const bool do_collection) +static void libblock_relink_collection(Main *bmain, + Collection *collection, + const bool do_collection) { if (do_collection) { - BKE_libblock_relink_to_newid(&collection->id); + BKE_libblock_relink_to_newid(bmain, &collection->id, 0); } for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { - BKE_libblock_relink_to_newid(&cob->ob->id); + BKE_libblock_relink_to_newid(bmain, &cob->ob->id, 0); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - libblock_relink_collection(child->collection, true); + libblock_relink_collection(bmain, child->collection, true); } } @@ -1766,10 +1768,10 @@ static void single_object_users( single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); /* Will also handle the master collection. */ - BKE_libblock_relink_to_newid(&scene->id); + BKE_libblock_relink_to_newid(bmain, &scene->id, 0); /* Collection and object pointers in collections */ - libblock_relink_collection(scene->master_collection, false); + libblock_relink_collection(bmain, scene->master_collection, false); /* We also have to handle runtime things in UI. */ if (v3d) { @@ -2654,7 +2656,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot) /* api callbacks */ ot->invoke = drop_named_material_invoke; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode_poll_msg; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 97f3b96cd18..fc80767be9e 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3903,8 +3903,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, co); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); @@ -3993,15 +3993,15 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(oco, key->co); mul_m4_v3(mat, oco); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, oco); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); if (point_index != -1) { copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */ - mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */ + mul_mat3_m4_v3(data->ob->obmat, onor); /* Normal into world-space. */ + mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ normalize_v3(onor); } else { diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 80c14371c16..38eadf95bde 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -594,7 +594,7 @@ void ED_region_do_draw(bContext *C, ARegion *region) memset(®ion->drawrct, 0, sizeof(region->drawrct)); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); if (area) { const bScreen *screen = WM_window_get_active_screen(win); @@ -1377,7 +1377,7 @@ static void region_rect_recursive( else if (alignment == RGN_ALIGN_FLOAT) { /** * \note Currently this window type is only used for #RGN_TYPE_HUD, - * We expect the panel to resize it's self to be larger. + * We expect the panel to resize itself to be larger. * * This aligns to the lower left of the area. */ @@ -1985,7 +1985,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area) } else { /* prevent uiblocks to run */ - UI_blocklist_free(NULL, ®ion->uiblocks); + UI_blocklist_free(NULL, region); } /* Some AZones use View2D data which is only updated in region init, so call that first! */ @@ -3323,7 +3323,7 @@ bool ED_region_property_search(const bContext *C, } /* Free the panels and blocks, as they are only used for search. */ - UI_blocklist_free(C, ®ion->uiblocks); + UI_blocklist_free(C, region); UI_panels_free_instanced(C, region); BKE_area_region_panels_free(®ion->panels); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index fa0cfd16817..3c8fb2e7446 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1495,8 +1495,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const * switching screens with tooltip open because region and tooltip * are no longer in the same screen */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); if (region->regiontimer) { WM_event_remove_timer(wm, NULL, region->regiontimer); region->regiontimer = NULL; diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index bc370c64b0c..4cad97652dd 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -111,7 +111,7 @@ bUserMenu *ED_screen_user_menu_ensure(bContext *C) bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, - short opcontext) + wmOperatorCallContext opcontext) { LISTBASE_FOREACH (bUserMenuItem *, umi, lb) { if (umi->type == USER_MENU_TYPE_OPERATOR) { @@ -160,7 +160,7 @@ void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, - short opcontext) + wmOperatorCallContext opcontext) { bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add( lb, USER_MENU_TYPE_OPERATOR); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 3b668a1bd4c..b826ff8701d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC paint_hide.c paint_image.c paint_image_2d.c + paint_image_2d_curve_mask.cc paint_image_proj.c paint_mask.c paint_ops.c diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 63f61b6c5c1..7191431cf4c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -78,12 +78,13 @@ typedef struct BrushPainterCache { ImBuf *ibuf; ImBuf *texibuf; - ushort *curve_mask; ushort *tex_mask; ushort *tex_mask_old; uint tex_mask_old_w; uint tex_mask_old_h; + CurveMaskCache curve_mask_cache; + int image_size[2]; } BrushPainterCache; @@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf( if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf( MEM_freeN(cache->tex_mask_old); } cache->ibuf = NULL; - cache->curve_mask = NULL; cache->tex_mask = NULL; cache->lastdiameter = -1; /* force ibuf create in refresh */ cache->invert = invert; @@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache) if (cache->texibuf) { IMB_freeImBuf(cache->texibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } + paint_curve_mask_cache_free_data(&cache->curve_mask_cache); if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -380,79 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, cache->tex_mask_old_h = diameter; } -/* create a mask with the falloff strength */ -static ushort *brush_painter_curve_mask_new(BrushPainter *painter, - int diameter, - float radius, - const float pos[2]) -{ - Brush *brush = painter->brush; - - int offset = (int)floorf(diameter / 2.0f); - - ushort *mask, *m; - - mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask"); - m = mask; - - int aa_samples = 1.0f / (radius * 0.20f); - if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { - aa_samples = clamp_i(aa_samples, 3, 16); - } - else { - aa_samples = 1; - } - - /* Temporal until we have the brush properties */ - const float hardness = 1.0f; - const float rotation = 0.0f; - - float aa_offset = 1.0f / (2.0f * (float)aa_samples); - float aa_step = 1.0f / (float)aa_samples; - - float bpos[2]; - bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset; - bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset; - - const float co = cosf(DEG2RADF(rotation)); - const float si = sinf(DEG2RADF(rotation)); - - float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); - - for (int y = 0; y < diameter; y++) { - for (int x = 0; x < diameter; x++, m++) { - float total_samples = 0; - for (int i = 0; i < aa_samples; i++) { - for (int j = 0; j < aa_samples; j++) { - float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; - float xy_rot[2]; - sub_v2_v2(pixel_xy, bpos); - - xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; - xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; - - float len = len_v2(xy_rot); - float p = len / radius; - if (hardness < 1.0f) { - p = (p - hardness) / (1.0f - hardness); - p = 1.0f - p; - CLAMP(p, 0.0f, 1.0f); - } - else { - p = 1.0; - } - float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; - float curve = BKE_brush_curve_strength_clamped(brush, len, radius); - total_samples += curve * hardness_factor; - } - } - *m = (ushort)(total_samples * norm_factor); - } - } - - return mask; -} - /* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new( BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance) @@ -858,10 +780,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } } - /* curve mask can only change if the size changes */ - MEM_SAFE_FREE(cache->curve_mask); - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* Re-initialize the curve mask. Mask is always recreated due to the change of position. */ + paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos); /* detect if we need to recreate image brush buffer */ if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random || @@ -1325,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s, &tmpbuf, frombuf, mask, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region->destx, @@ -1474,7 +1394,7 @@ static int paint_2d_op(void *state, canvas, frombuf, NULL, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region[a].destx, diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc new file mode 100644 index 00000000000..8d57a3d9152 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc @@ -0,0 +1,188 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup ed + */ + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" + +#include "BKE_brush.h" + +#include "paint_intern.h" + +namespace blender::ed::sculpt_paint { + +constexpr int AntiAliasingSamplesPerTexelAxisMin = 3; +constexpr int AntiAliasingSamplesPerTexelAxisMax = 16; +/** + * \brief Number of samples to use between 0..1. + */ +constexpr int CurveSamplesBaseLen = 1024; +/** + * \brief Number of samples to store in the cache. + * + * M_SQRT2 is used as brushes are circles and the curve_mask is square. + * + 1 to fix floating rounding issues. + */ +constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1; + +static int aa_samples_per_texel_axis(const Brush *brush, const float radius) +{ + int aa_samples = 1.0f / (radius * 0.20f); + if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { + aa_samples = clamp_i( + aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax); + } + else { + aa_samples = 1; + } + return aa_samples; +} + +/* create a mask with the falloff strength */ +static void update_curve_mask(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + BLI_assert(curve_mask_cache->curve_mask != nullptr); + int offset = (int)floorf(diameter / 2.0f); + + unsigned short *m = curve_mask_cache->curve_mask; + + const int aa_samples = aa_samples_per_texel_axis(brush, radius); + const float aa_offset = 1.0f / (2.0f * (float)aa_samples); + const float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset; + bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset; + + float weight_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float pixel_xy[2]; + pixel_xy[0] = static_cast<float>(x) + aa_offset; + float total_weight = 0; + + for (int i = 0; i < aa_samples; i++) { + pixel_xy[1] = static_cast<float>(y) + aa_offset; + for (int j = 0; j < aa_samples; j++) { + const float len = len_v2v2(pixel_xy, bpos); + const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen, + CurveSamplesLen - 1); + const float sample_weight = curve_mask_cache->sampled_curve[sample_index]; + + total_weight += sample_weight; + + pixel_xy[1] += aa_step; + } + pixel_xy[0] += aa_step; + } + *m = (unsigned short)(total_weight * weight_factor); + } + } +} + +static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + return false; + } + return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp; +} + +static void sampled_curve_free(CurveMaskCache *curve_mask_cache) +{ + MEM_SAFE_FREE(curve_mask_cache->sampled_curve); + curve_mask_cache->last_curve_timestamp = 0; +} + +static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + curve_mask_cache->sampled_curve = static_cast<float *>( + MEM_mallocN(CurveSamplesLen * sizeof(float), __func__)); + } + + for (int i = 0; i < CurveSamplesLen; i++) { + const float len = i / float(CurveSamplesBaseLen); + const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f); + curve_mask_cache->sampled_curve[i] = sample_weight; + } + curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp; +} + +static size_t diameter_to_curve_mask_size(const int diameter) +{ + return diameter * diameter * sizeof(ushort); +} + +static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter) +{ + return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter); +} + +static void curve_mask_free(CurveMaskCache *curve_mask_cache) +{ + curve_mask_cache->curve_mask_size = 0; + MEM_SAFE_FREE(curve_mask_cache->curve_mask); +} + +static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter) +{ + const size_t curve_mask_size = diameter_to_curve_mask_size(diameter); + curve_mask_cache->curve_mask = static_cast<unsigned short *>( + MEM_mallocN(curve_mask_size, __func__)); + curve_mask_cache->curve_mask_size = curve_mask_size; +} + +} // namespace blender::ed::sculpt_paint + +using namespace blender::ed::sculpt_paint; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache) +{ + sampled_curve_free(curve_mask_cache); + curve_mask_free(curve_mask_cache); +} + +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + if (!is_sampled_curve_valid(curve_mask_cache, brush)) { + update_sampled_curve(curve_mask_cache, brush); + } + + if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) { + curve_mask_free(curve_mask_cache); + curve_mask_allocate(curve_mask_cache, diameter); + } + update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 89263bec7b1..db3e69b0953 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3125,7 +3125,8 @@ static void project_paint_face_init(const ProjPaintState *ps, uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); } - /* a pity we need to get the worldspace pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, ps->mvert_eval[lt_vtri[0]].co, @@ -3208,7 +3209,10 @@ static void project_paint_face_init(const ProjPaintState *ps, else { /* we have a seam - deal with it! */ - /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */ + /* Inset face coords. + * - screen-space in orthographic view. + * - world-space in perspective view. + */ float insetCos[3][3]; /* Vertex screen-space coords. */ @@ -3373,8 +3377,8 @@ static void project_paint_face_init(const ProjPaintState *ps, if ((ps->do_occlude == false) || !project_bucket_point_occluded( ps, bucketFaceNodes, tri_index, pixel_on_edge)) { - /* a pity we need to get the worldspace - * pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 7341d984c91..62320defbb3 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -23,6 +23,13 @@ #pragma once +#include "BKE_paint.h" +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + struct ARegion; struct Brush; struct ColorManagedDisplay; @@ -43,8 +50,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -enum ePaintMode; -enum ePaintSymmetryFlags; typedef struct CoNo { float co[3]; @@ -245,6 +250,45 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); +/* paint_image_2d_curve_mask.cc */ +/** + * \brief Caching structure for curve mask. + * + * When 2d painting images the curve mask is used as an input. + */ +typedef struct CurveMaskCache { + /** + * \brief Last #CurveMapping.changed_timestamp being read. + * + * When different the input cache needs to be recalculated. + */ + int last_curve_timestamp; + + /** + * \brief sampled version of the brush curvemapping. + */ + float *sampled_curve; + + /** + * \brief Size in bytes of the curve_mask field. + * + * Used to determine if the curve_mask needs to be re-allocated. + */ + size_t curve_mask_size; + + /** + * \brief Curve mask that can be passed as curve_mask parameter when. + */ + ushort *curve_mask; +} CurveMaskCache; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache); +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const struct Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]); + /* sculpt_uv.c */ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot); @@ -366,3 +410,8 @@ void paint_delete_blur_kernel(BlurKernel *); /* paint curve defines */ #define PAINT_CURVE_NUM_SEGMENTS 40 + +#ifdef __cplusplus +} +#endif + diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index f95e1d8d89c..f62d91acddf 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -210,9 +210,6 @@ static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag) int(*scol)[4]; bool has_shared = false; - /* if no mloopcol: do not do */ - /* if mtexpoly: only the involved faces, otherwise all */ - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) { return; } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 696c3332a2b..16df1efd969 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -366,10 +366,12 @@ float *SCULPT_boundary_automasking_init(Object *ob, /* Geodesic distances. */ -/* Returns an array indexed by vertex index containing the geodesic distance to the closest vertex -in the initial vertex set. The caller is responsible for freeing the array. -Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will -fallback to euclidean distances to one of the initial vertices in the set. */ +/** + * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex + * in the initial vertex set. The caller is responsible for freeing the array. + * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will + * fallback to euclidean distances to one of the initial vertices in the set. + */ float *SCULPT_geodesic_distances_create(struct Object *ob, struct GSet *initial_vertices, const float limit_radius); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index a4fd2d81778..9ff46d96207 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -702,6 +702,9 @@ void ACTION_OT_unlink(wmOperatorType *ot) "Clear Fake User and remove " "copy stashed in this data-block's NLA stack"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index b04291b7ab4..bc701bd7aa5 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -445,7 +445,7 @@ static void property_search_all_tabs(const bContext *C, i, property_search_for_context(C, region_copy, &sbuts_copy)); - UI_blocklist_free(C, ®ion_copy->uiblocks); + UI_blocklist_free(C, region_copy); } BKE_area_region_free(area_copy.type, region_copy); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 834ef847069..97fcf4ef8ba 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -272,7 +272,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale } bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]) { @@ -282,7 +282,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc, } /* map the mouse coords to the backdrop image space */ - ED_clip_mouse_pos(sc, ar, mval, fpos); + ED_clip_mouse_pos(sc, region, mval, fpos); IMB_freeImBuf(ibuf); return true; diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 41559278910..dee5168e30b 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -191,7 +191,8 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive( { ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>( &catalog); - view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); + view_item.set_is_active_fn( + [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) { build_catalog_items_recursive(view_item, child); @@ -205,11 +206,11 @@ void AssetCatalogTreeView::add_all_item() AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"), ICON_HOME); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; }); } @@ -220,11 +221,11 @@ void AssetCatalogTreeView::add_unassigned_item() AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>( IFACE_("Unassigned"), ICON_FILE_HIDDEN); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; }); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 51a5c451f6d..6f929c43e13 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1710,7 +1710,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry return; } - if (entry->flags & FILE_ENTRY_INVALID_PREVIEW) { + if (entry->flags & (FILE_ENTRY_INVALID_PREVIEW | FILE_ENTRY_PREVIEW_LOADING)) { return; } @@ -1741,6 +1741,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), __func__); preview_taskdata->preview = preview; + entry->flags |= FILE_ENTRY_PREVIEW_LOADING; BLI_task_pool_push(cache->previews_pool, filelist_cache_preview_runf, preview_taskdata, @@ -1896,6 +1897,7 @@ static void filelist_clear_asset_library(FileList *filelist) { /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */ filelist->asset_library = NULL; + file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter); } void filelist_clear_ex(struct FileList *filelist, @@ -1995,7 +1997,6 @@ void filelist_free(struct FileList *filelist) filelist->selection_state = NULL; } - file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter); MEM_SAFE_FREE(filelist->asset_library_ref); memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); @@ -2659,24 +2660,27 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->icon_id) { - /* Due to asynchronous process, a preview for a given image may be generated several times, - * i.e. entry->image may already be set at this point. */ - if (entry && !entry->preview_icon_id) { + if (entry) { + if (preview->icon_id) { + /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous + * process from trying to generate the same preview icon. */ + BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet"); + /* Move ownership over icon. */ entry->preview_icon_id = preview->icon_id; preview->icon_id = 0; changed = true; } else { - BKE_icon_delete(preview->icon_id); + /* We want to avoid re-processing this entry continuously! + * Note that, since entries only live in cache, + * preview will be retried quite often anyway. */ + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; } + entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING; } - else if (entry) { - /* We want to avoid re-processing this entry continuously! - * Note that, since entries only live in cache, - * preview will be retried quite often anyway. */ - entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + else { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 26a056ce1fb..41f74b6ade9 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -19,6 +19,8 @@ /** \file * \ingroup spgraph + * + * Graph editor space & buttons. */ #include <float.h> @@ -66,11 +68,11 @@ #include "graph_intern.h" /* own include */ -/* ******************* graph editor space & buttons ************** */ - #define B_REDR 1 -/* -------------- */ +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu) { @@ -120,7 +122,11 @@ static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt)) return graph_panel_context(C, NULL, NULL); } -/* -------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cursor Header + * \{ */ static void graph_panel_cursor_header(const bContext *C, Panel *panel) { @@ -174,7 +180,11 @@ static void graph_panel_cursor(const bContext *C, Panel *panel) uiItemO(sub, IFACE_("Cursor Value to Selection"), ICON_NONE, "GRAPH_OT_snap_cursor_value"); } -/* ******************* active F-Curve ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active F-Curve + * \{ */ static void graph_panel_properties(const bContext *C, Panel *panel) { @@ -243,7 +253,11 @@ static void graph_panel_properties(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* active Keyframe ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active Keyframe + * \{ */ /* get 'active' keyframe for panel editing */ static bool get_active_fcurve_keyframe_edit(const FCurve *fcu, @@ -610,7 +624,11 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* drivers ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drivers + * \{ */ #define B_IPO_DEPCHANGE 10 @@ -1320,8 +1338,13 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *panel) uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show"); } -/* ******************* F-Modifiers ******************************** */ -/* All the drawing code is in editors/animation/fmodifier_ui.c */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name F-Curve Modifiers + * + * \note All the drawing code is in `editors/animation/fmodifier_ui.c` + * \{ */ #define B_FMODIFIER_REDRAW 20 /** The start of FModifier panels registered for the graph editor. */ @@ -1380,7 +1403,11 @@ static void graph_panel_modifiers(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* general ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration + * \{ */ void graph_buttons_register(ARegionType *art) { @@ -1456,3 +1483,5 @@ void graph_buttons_register(ARegionType *art) pt->draw_header = graph_panel_cursor_header; BLI_addtail(&art->paneltypes, pt); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 1967dfabd21..2afee277847 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -19,6 +19,8 @@ /** \file * \ingroup spgraph + * + * Insert duplicate and bake keyframes. */ #include <float.h> @@ -69,9 +71,6 @@ #include "graph_intern.h" -/* ************************************************************************** */ -/* INSERT DUPLICATE AND BAKE KEYFRAMES */ - /* -------------------------------------------------------------------- */ /** \name Insert Keyframes Operator * \{ */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 32396a70cce..ecafc75fc06 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -52,11 +52,13 @@ /* ************************** view-based operators **********************************/ /* XXX should these really be here? */ -/* Set Cursor --------------------------------------------------------------------- */ -/* The 'cursor' in the Graph Editor consists of two parts: +/* -------------------------------------------------------------------- */ +/** \name Set Cursor + * + * The 'cursor' in the Graph Editor consists of two parts: * 1) Current Frame Indicator (as per ANIM_OT_change_frame) * 2) Value Indicator (stored per Graph Editor instance) - */ + * \{ */ static bool graphview_cursor_poll(bContext *C) { @@ -225,7 +227,11 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f); } -/* Hide/Reveal ------------------------------------------------------------ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide/Reveal + * \{ */ static int graphview_curves_hide_exec(bContext *C, wmOperator *op) { @@ -413,7 +419,11 @@ static void GRAPH_OT_reveal(wmOperatorType *ot) RNA_def_boolean(ot->srna, "select", true, "Select", ""); } -/* ************************** registration - operator types **********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration: operator types + * \{ */ void graphedit_operatortypes(void) { @@ -496,7 +506,11 @@ void ED_operatormacros_graph(void) RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); } -/* ************************** registration - keymaps **********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration: Key-Maps + * \{ */ void graphedit_keymap(wmKeyConfig *keyconf) { @@ -514,3 +528,5 @@ void graphedit_keymap(wmKeyConfig *keyconf) /* keyframes */ WM_keymap_ensure(keyconf, "Graph Editor", SPACE_GRAPH, 0); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index ffe74e20bdf..03bfd1092c6 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -56,8 +56,9 @@ #include "graph_intern.h" -/* ************************************************************************** */ -/* KEYFRAMES STUFF */ +/* -------------------------------------------------------------------- */ +/** \name Internal Keyframe Utilities + * \{ */ /* temp info for caching handle vertices close */ typedef struct tNearestVertInfo { @@ -334,14 +335,19 @@ static tNearestVertInfo *find_nearest_fcurve_vert(bAnimContext *ac, const int mv return nvi; } -/* ******************** Deselect All Operator ***************************** */ -/* This operator works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deselect All Operator + * + * This operator works in one of three ways: * 1) (de)select all (AKEY) - test if select all or deselect all * 2) invert all (CTRL-IKEY) - invert selection of all keyframes * 3) (de)select all - no testing is done; only for use internal tools as normal function... - */ + * \{ */ -/* Deselects keyframes in the Graph Editor +/** + * Deselects keyframes in the Graph Editor * - This is called by the deselect all operator, as well as other ones! * * - test: check if select or deselect all @@ -490,8 +496,12 @@ void GRAPH_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ******************** Box Select Operator **************************** */ -/* This operator currently works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * + * This operator currently works in one of three ways: * -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION) * -> ALT-BKEY - depending on which axis of the region was larger... * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) @@ -499,7 +509,7 @@ void GRAPH_OT_select_all(wmOperatorType *ot) * (validation with BEZT_OK_VALUERANGE). * * The selection backend is also reused for the Lasso and Circle select operators. - */ + * \{ */ static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view) { @@ -572,7 +582,8 @@ static void initialize_box_select_key_editing_data(const SpaceGraph *sipo, *r_mapping_flag |= ANIM_get_normalization_flags(ac); } -/* Box Select only selects keyframes, as overshooting handles often get caught too, +/** + * Box Select only selects keyframes, as overshooting handles often get caught too, * which means that they may be inadvertently moved as well. However, incl_handles overrides * this, and allow handles to be considered independently too. * Also, for convenience, handles should get same status as keyframe (if it was within bounds). @@ -667,7 +678,8 @@ static bool box_select_graphkeys(bAnimContext *ac, return any_key_selection_changed; } -/* This function is used to set all the keyframes of a given curve as selectable +/** + * This function is used to set all the keyframes of a given curve as selectable * by the "select_cb" function inside of "box_select_graphcurves". */ static short ok_bezier_always_ok(KeyframeEditData *UNUSED(ked), BezTriple *UNUSED(bezt)) @@ -732,11 +744,12 @@ static bool rectf_curve_intersection( #undef INSIDE #undef BELOW -/* Perform a box selection of the curves themselves. This means this function tries +/** + * Perform a box selection of the curves themselves. This means this function tries * to select a curve by sampling it at various points instead of trying to select the * keyframes directly. * The selection actions done to a curve are actually done on all the keyframes of the curve. - * NOTE: This function is only called if no keyframe is in the selection area. + * \note This function is only called if no keyframe is in the selection area. */ static void box_select_graphcurves(bAnimContext *ac, const rctf *rectf_view, @@ -1107,13 +1120,17 @@ void GRAPH_OT_select_circle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Column Select Operator **************************** */ -/* This operator works in one of four ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Column Select Operator + * + * This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) * - 4) select all keyframes that occur between selected markers (ALT-KKEY) - */ + * \{ */ /* defines for column-select mode */ static const EnumPropertyItem prop_column_select_types[] = { @@ -1297,7 +1314,11 @@ void GRAPH_OT_select_column(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); } -/* ******************** Select Linked Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1353,7 +1374,11 @@ void GRAPH_OT_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select More/Less Operators *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operators + * \{ */ /* Common code to perform selection */ static void select_moreless_graph_keys(bAnimContext *ac, short mode) @@ -1467,8 +1492,13 @@ void GRAPH_OT_select_less(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select Left/Right Operator ************************* */ -/* Select keyframes left/right of the current frame indicator */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Left/Right Operator + * + * Select keyframes left/right of the current frame indicator. + * \{ */ /* defines for left-right select tool */ static const EnumPropertyItem prop_graphkeys_leftright_select_types[] = { @@ -1628,15 +1658,19 @@ void GRAPH_OT_select_leftright(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Mouse-Click Select Operator *********************** */ -/* This operator works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse-Click Select Operator + * + * This operator works in one of three ways: * - 1) keyframe under mouse - no special modifiers * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier * - 3) column select all keyframes in frame under mouse - CTRL modifier * * In addition to these basic options, the SHIFT modifier can be used to toggle the * selection mode between replacing the selection (without) and inverting the selection (with). - */ + * \{ */ /* option 1) select keyframe directly under mouse */ static int mouse_graph_keys(bAnimContext *ac, @@ -1888,9 +1922,12 @@ static int graphkeys_mselect_column(bAnimContext *ac, return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED; } -/* ------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Click Select Operator + * \{ */ -/* handle clicking */ static int graphkeys_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -1988,4 +2025,4 @@ void GRAPH_OT_clickselect(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index f04336cab84..4e62ab2df2d 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -17,6 +17,16 @@ * All rights reserved. */ +/** \file + * \ingroup spgraph + * + * Graph Slider Operators + * + * This file contains a collection of operators to modify keyframes in the graph editor. + * All operators are modal and use a slider that allows the user to define a percentage + * to modify the operator. + */ + #include <float.h> #include <string.h> @@ -48,42 +58,17 @@ #include "graph_intern.h" -/* ******************** GRAPH SLIDER OPERATORS ************************* */ -/* This file contains a collection of operators to modify keyframes in the graph editor. All - * operators are modal and use a slider that allows the user to define a percentage to modify the - * operator. */ - -/* ******************** Decimate Keyframes Operator ************************* */ - -static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Loop through filtered data and clean curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { - /* The selection contains unsupported keyframe types! */ - WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); -} +/* -------------------------------------------------------------------- */ +/** \name Internal Struct & Defines + * \{ */ -/* ------------------- */ +/* Used to obtain a list of animation channels for the operators to work on. */ +#define OPERATOR_DATA_FILTER \ + (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | \ + ANIMFILTER_NODUPLIS) /* This data type is only used for modal operation. */ -typedef struct tDecimateGraphOp { +typedef struct tGraphSliderOp { bAnimContext ac; Scene *scene; ScrArea *area; @@ -98,35 +83,73 @@ typedef struct tDecimateGraphOp { struct tSlider *slider; NumInput num; -} tDecimateGraphOp; +} tGraphSliderOp; typedef struct tBeztCopyData { int tot_vert; BezTriple *bezt; } tBeztCopyData; -typedef enum tDecimModes { - DECIM_RATIO = 1, - DECIM_ERROR, -} tDecimModes; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utility Functions + * \{ */ + +/* Construct a list with the original bezt arrays so we can restore them during modal operation. + * The data is stored on the struct that is passed.*/ +static void store_original_bezt_arrays(tGraphSliderOp *gso) +{ + ListBase anim_data = {NULL, NULL}; + bAnimContext *ac = &gso->ac; + bAnimListElem *ale; + + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + /* Loop through filtered data and copy the curves. */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + + if (fcu->bezt == NULL) { + /* This curve is baked, skip it. */ + continue; + } + + const int arr_size = sizeof(BezTriple) * fcu->totvert; + + tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); + BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); + + copy->tot_vert = fcu->totvert; + memcpy(bezts_copy, fcu->bezt, arr_size); + + copy->bezt = bezts_copy; + + LinkData *link = NULL; + + link = MEM_callocN(sizeof(LinkData), "Bezt Link"); + link->data = copy; + + BLI_addtail(&gso->bezt_arr_list, link); + } + + ANIM_animdata_freelist(&anim_data); +} /* Overwrite the current bezts arrays with the original data. */ -static void decimate_reset_bezts(tDecimateGraphOp *dgo) +static void reset_bezts(tGraphSliderOp *gso) { ListBase anim_data = {NULL, NULL}; LinkData *link_bezt; bAnimListElem *ale; - int filter; - bAnimContext *ac = &dgo->ac; + bAnimContext *ac = &gso->ac; /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); /* Loop through filtered data and reset bezts. */ - for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) { + for (ale = anim_data.first, link_bezt = gso->bezt_arr_list.first; ale; ale = ale->next) { FCurve *fcu = (FCurve *)ale->key_data; if (fcu->bezt == NULL) { @@ -151,29 +174,62 @@ static void decimate_reset_bezts(tDecimateGraphOp *dgo) ANIM_animdata_freelist(&anim_data); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Decimate Keyframes Operator + * \{ */ + +typedef enum tDecimModes { + DECIM_RATIO = 1, + DECIM_ERROR, +} tDecimModes; + +static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + + /* Filter data. */ + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + /* Loop through filtered data and clean curves. */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { + /* The selection contains unsupported keyframe types! */ + WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + static void decimate_exit(bContext *C, wmOperator *op) { - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; wmWindow *win = CTX_wm_window(C); /* If data exists, clear its data and exit. */ - if (dgo == NULL) { + if (gso == NULL) { return; } - ScrArea *area = dgo->area; + ScrArea *area = gso->area; LinkData *link; - ED_slider_destroy(C, dgo->slider); + ED_slider_destroy(C, gso->slider); - for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) { + for (link = gso->bezt_arr_list.first; link != NULL; link = link->next) { tBeztCopyData *copy = link->data; MEM_freeN(copy->bezt); MEM_freeN(link->data); } - BLI_freelistN(&dgo->bezt_arr_list); - MEM_freeN(dgo); + BLI_freelistN(&gso->bezt_arr_list); + MEM_freeN(gso); /* Return to normal cursor and header status. */ WM_cursor_modal_restore(win); @@ -184,20 +240,20 @@ static void decimate_exit(bContext *C, wmOperator *op) } /* Draw a percentage indicator in workspace footer. */ -static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo) +static void decimate_draw_status(bContext *C, tGraphSliderOp *gso) { char status_str[UI_MAX_DRAW_STR]; char mode_str[32]; char slider_string[UI_MAX_DRAW_STR]; - ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR); + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); strcpy(mode_str, TIP_("Decimate Keyframes")); - if (hasNumInput(&dgo->num)) { + if (hasNumInput(&gso->num)) { char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit); + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); } @@ -210,76 +266,34 @@ static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo) static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tDecimateGraphOp *dgo; + tGraphSliderOp *gso; WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL); /* Init slide-op data. */ - dgo = op->customdata = MEM_callocN(sizeof(tDecimateGraphOp), "tDecimateGraphOp"); + gso = op->customdata = MEM_callocN(sizeof(tGraphSliderOp), "tGraphSliderOp"); /* Get editor data. */ - if (ANIM_animdata_get_context(C, &dgo->ac) == 0) { + if (ANIM_animdata_get_context(C, &gso->ac) == 0) { decimate_exit(C, op); return OPERATOR_CANCELLED; } - dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio"); - - dgo->scene = CTX_data_scene(C); - dgo->area = CTX_wm_area(C); - dgo->region = CTX_wm_region(C); - - dgo->slider = ED_slider_create(C); - ED_slider_init(dgo->slider, event); - ED_slider_allow_overshoot_set(dgo->slider, false); - - decimate_draw_status(C, dgo); - - /* Construct a list with the original bezt arrays so we can restore them during modal operation. - */ - { - ListBase anim_data = {NULL, NULL}; - bAnimContext *ac = &dgo->ac; - bAnimListElem *ale; + gso->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio"); - int filter; + gso->scene = CTX_data_scene(C); + gso->area = CTX_wm_area(C); + gso->region = CTX_wm_region(C); - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + store_original_bezt_arrays(gso); - /* Loop through filtered data and copy the curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; + gso->slider = ED_slider_create(C); + ED_slider_init(gso->slider, event); + ED_slider_allow_overshoot_set(gso->slider, false); - if (fcu->bezt == NULL) { - /* This curve is baked, skip it. */ - continue; - } - - const int arr_size = sizeof(BezTriple) * fcu->totvert; - - tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); - BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); - - copy->tot_vert = fcu->totvert; - memcpy(bezts_copy, fcu->bezt, arr_size); - - copy->bezt = bezts_copy; - - LinkData *link = NULL; + decimate_draw_status(C, gso); - link = MEM_callocN(sizeof(LinkData), "Bezt Link"); - link->data = copy; - - BLI_addtail(&dgo->bezt_arr_list, link); - } - - ANIM_animdata_freelist(&anim_data); - } - - if (dgo->bezt_arr_list.first == NULL) { + if (gso->bezt_arr_list.first == NULL) { WM_report(RPT_WARNING, "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again."); decimate_exit(C, op); @@ -294,19 +308,19 @@ static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op) { /* Perform decimate updates - in response to some user action * (e.g. pressing a key or moving the mouse). */ - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; - decimate_draw_status(C, dgo); + decimate_draw_status(C, gso); /* Reset keyframe data (so we get back to the original state). */ - decimate_reset_bezts(dgo); + reset_bezts(gso); /* Apply... */ - float remove_ratio = ED_slider_factor_get(dgo->slider); - RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio); + float remove_ratio = ED_slider_factor_get(gso->slider); + RNA_property_float_set(op->ptr, gso->percentage_prop, remove_ratio); /* We don't want to limit the decimation to a certain error margin. */ const float error_sq_max = FLT_MAX; - decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max); + decimate_graph_keys(&gso->ac, remove_ratio, error_sq_max); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } @@ -316,11 +330,11 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * * and finicky to control with this modal mouse grab method. Therefore, it is expected that the * error margin mode is not adjusted by the modal operator but instead tweaked via the redo * panel. */ - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; - const bool has_numinput = hasNumInput(&dgo->num); + const bool has_numinput = hasNumInput(&gso->num); - ED_slider_modal(dgo->slider, event); + ED_slider_modal(gso->slider, event); switch (event->type) { case LEFTMOUSE: /* Confirm */ @@ -337,7 +351,7 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * case EVT_ESCKEY: /* Cancel */ case RIGHTMOUSE: { if (event->val == KM_PRESS) { - decimate_reset_bezts(dgo); + reset_bezts(gso); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); @@ -358,18 +372,18 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * break; } default: { - if ((event->val == KM_PRESS) && handleNumInput(C, &dgo->num, event)) { + if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) { float value; - float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); + float percentage = RNA_property_float_get(op->ptr, gso->percentage_prop); /* Grab percentage from numeric input, and store this new value for redo * NOTE: users see ints, while internally we use a 0-1 float. */ value = percentage * 100.0f; - applyNumInput(&dgo->num, &value); + applyNumInput(&gso->num, &value); percentage = value / 100.0f; - RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); + RNA_property_float_set(op->ptr, gso->percentage_prop, percentage); /* Update decimate output to reflect the new values. */ graphkeys_decimate_modal_update(C, op); @@ -520,3 +534,5 @@ void GRAPH_OT_decimate(wmOperatorType *ot) 0.0f, 10.0f); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index c37d9f42c12..89e7fefd9ac 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -46,8 +46,9 @@ #include "graph_intern.h" /* own include */ -/* ************************************************************** */ -/* Set Up Drivers Editor */ +/* -------------------------------------------------------------------- */ +/** \name Set Up Drivers Editor + * \{ */ /* Set up UI configuration for Drivers Editor */ /* NOTE: Currently called from window-manager @@ -89,8 +90,11 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area) } } -/* ************************************************************** */ -/* Active F-Curve */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active F-Curve + * \{ */ /** * Find 'active' F-Curve. @@ -124,8 +128,11 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac) return NULL; } -/* ************************************************************** */ -/* Operator Polling Callbacks */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Polling Callbacks + * \{ */ /* Check if there are any visible keyframes (for selection tools) */ bool graphop_visible_keyframes_poll(bContext *C) @@ -321,4 +328,4 @@ bool graphop_selected_fcurve_poll(bContext *C) return true; } -/* ************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index 56649c50cfd..a12c6053877 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -17,6 +17,10 @@ * All rights reserved. */ +/** \file + * \ingroup spgraph + */ + #include <math.h> #include "MEM_guardedalloc.h" @@ -48,7 +52,9 @@ #include "graph_intern.h" -/* *************************** Calculate Range ************************** */ +/* -------------------------------------------------------------------- */ +/** \name Calculate Range + * \{ */ /* Get the min/max keyframes. */ /* NOTE: it should return total boundbox, filter for selection only can be argument... */ @@ -194,7 +200,11 @@ void get_graph_keyframe_extents(bAnimContext *ac, } } -/* ****************** Automatic Preview-Range Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Automatic Preview-Range Operator + * \{ */ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -241,7 +251,11 @@ void GRAPH_OT_previewrange_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ****************** View-All Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View-All Operator + * \{ */ static int graphkeys_viewall(bContext *C, const bool do_sel_only, @@ -347,7 +361,11 @@ void GRAPH_OT_view_selected(wmOperatorType *ot) "Include handles of keyframes when calculating extents"); } -/* ********************** View Frame Operator ****************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Frame Operator + * \{ */ static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) { @@ -371,10 +389,14 @@ void GRAPH_OT_view_frame(wmOperatorType *ot) ot->flag = 0; } -/* ******************** Create Ghost-Curves Operator *********************** */ -/* This operator samples the data of the selected F-Curves to F-Points, storing them +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Create Ghost-Curves Operator + * + * This operator samples the data of the selected F-Curves to F-Points, storing them * as 'ghost curves' in the active Graph Editor. - */ + * \{ */ /* Bake each F-Curve into a set of samples, and store as a ghost curve. */ static void create_ghost_curves(bAnimContext *ac, int start, int end) @@ -493,8 +515,13 @@ void GRAPH_OT_ghost_curves_create(wmOperatorType *ot) /* TODO: add props for start/end frames */ } -/* ******************** Clear Ghost-Curves Operator *********************** */ -/* This operator clears the 'ghost curves' for the active Graph Editor */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Ghost-Curves Operator + * + * This operator clears the 'ghost curves' for the active Graph Editor. + * \{ */ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -534,3 +561,5 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 22a43ea3794..d76b1842c94 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -185,7 +185,7 @@ void ED_image_draw_info(Scene *scene, GPU_blend(GPU_BLEND_NONE); - BLF_size(blf_mono_font, 11 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 11.0f * U.pixelsize, U.dpi); BLF_color3ub(blf_mono_font, 255, 255, 255); SNPRINTF(str, "X:%-4d Y:%-4d |", x, y); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 478e484924a..44794439f5f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3191,7 +3191,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot) * \{ */ /* Returns mouse position in image space. */ -bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2]) +bool ED_space_image_get_position(SpaceImage *sima, + struct ARegion *region, + int mval[2], + float fpos[2]) { void *lock; ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0); @@ -3201,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[ return false; } - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); + UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); ED_space_image_release_buffer(sima, ibuf, lock); return true; diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index b6df07eec4e..144b21fb9b8 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -37,7 +37,7 @@ set(SRC info_draw.c info_ops.c info_report.c - info_stats.c + info_stats.cc space_info.c textview.c diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.cc index 13d15bc50a6..19c98fb4d17 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.cc @@ -18,8 +18,8 @@ * \ingroup spinfo */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -70,9 +70,11 @@ #include "GPU_capabilities.h" +ENUM_OPERATORS(eUserpref_StatusBar_Flag, STATUSBAR_SHOW_VERSION) + #define MAX_INFO_NUM_LEN 16 -typedef struct SceneStats { +struct SceneStats { uint64_t totvert, totvertsel, totvertsculpt; uint64_t totedge, totedgesel; uint64_t totface, totfacesel, totfacesculpt; @@ -81,9 +83,9 @@ typedef struct SceneStats { uint64_t totlamp, totlampsel; uint64_t tottri; uint64_t totgplayer, totgpframe, totgpstroke, totgppoint; -} SceneStats; +}; -typedef struct SceneStatsFmt { +struct SceneStatsFmt { /* Totals */ char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN]; char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN]; @@ -94,16 +96,16 @@ typedef struct SceneStatsFmt { char tottri[MAX_INFO_NUM_LEN]; char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN]; char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN]; -} SceneStatsFmt; +}; static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *stats) { - if (me_eval == NULL) { + if (me_eval == nullptr) { return false; } int totvert, totedge, totface, totloop; - if (me_eval->runtime.subdiv_ccg != NULL) { + if (me_eval->runtime.subdiv_ccg != nullptr) { const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop); } @@ -166,14 +168,14 @@ static void stats_object(Object *ob, case OB_CURVE: case OB_FONT: { const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); - if ((me_eval != NULL) && !BLI_gset_add(objects_gset, (void *)me_eval)) { + if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) { break; } if (stats_mesheval(me_eval, is_selected, stats)) { break; } - ATTR_FALLTHROUGH; /* Fallthrough to displist. */ + ATTR_FALLTHROUGH; /* Fall-through to displist. */ } case OB_MBALL: { int totv = 0, totf = 0, tottri = 0; @@ -242,10 +244,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_ARMATURE) { /* Armature Edit */ - bArmature *arm = obedit->data; - EditBone *ebo; + bArmature *arm = static_cast<bArmature *>(obedit->data); - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { + LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { stats->totbone++; if ((ebo->flag & BONE_CONNECTED) && ebo->parent) { @@ -274,14 +275,13 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */ /* Curve Edit */ - Curve *cu = obedit->data; - Nurb *nu; + Curve *cu = static_cast<Curve *>(obedit->data); BezTriple *bezt; BPoint *bp; int a; ListBase *nurbs = BKE_curve_editNurbs_get(cu); - for (nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; @@ -314,10 +314,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_MBALL) { /* MetaBall Edit */ - MetaBall *mball = obedit->data; - MetaElem *ml; + MetaBall *mball = static_cast<MetaBall *>(obedit->data); - for (ml = mball->editelems->first; ml; ml = ml->next) { + LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) { stats->totvert++; if (ml->flag & SELECT) { stats->totvertsel++; @@ -326,7 +325,7 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_LATTICE) { /* Lattice Edit */ - Lattice *lt = obedit->data; + Lattice *lt = static_cast<Lattice *>(obedit->data); Lattice *editlatt = lt->editlatt->latt; BPoint *bp; int a; @@ -347,10 +346,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) static void stats_object_pose(const Object *ob, SceneStats *stats) { if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; + bArmature *arm = static_cast<bArmature *>(ob->data); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { stats->totbone++; if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { if (pchan->bone->layer & arm->layer) { @@ -372,7 +370,7 @@ static void stats_object_sculpt(const Object *ob, SceneStats *stats) SculptSession *ss = ob->sculpt; - if (ss == NULL || ss->pbvh == NULL) { + if (ss == nullptr || ss->pbvh == nullptr) { return; } @@ -460,7 +458,7 @@ static void stats_update(Depsgraph *depsgraph, stats_object(ob_iter, v3d_local, stats, objects_gset); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; - BLI_gset_free(objects_gset, NULL); + BLI_gset_free(objects_gset, nullptr); } } @@ -476,7 +474,7 @@ void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer) const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = (View3D *)area->spacedata.first; if (v3d->localvd) { MEM_SAFE_FREE(v3d->runtime.local_stats); } @@ -490,14 +488,14 @@ static bool format_stats( { /* Create stats if they don't already exist. */ SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats; - if (*stats_p == NULL) { + if (*stats_p == nullptr) { /* Don't access dependency graph if interface is marked as locked. */ - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; if (wm->is_interface_locked) { return false; } Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer); - *stats_p = MEM_mallocN(sizeof(SceneStats), __func__); + *stats_p = (SceneStats *)MEM_mallocN(sizeof(SceneStats), __func__); stats_update(depsgraph, view_layer, v3d_local, *stats_p); } @@ -542,7 +540,7 @@ static void get_stats_string( { Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; LayerCollection *layer_collection = view_layer->active_collection; if (object_mode == OB_MODE_OBJECT) { @@ -646,7 +644,7 @@ static const char *info_statusbar_string(Main *bmain, /* Scene statistics. */ if (statusbar_flag & STATUSBAR_SHOW_STATS) { SceneStatsFmt stats_fmt; - if (format_stats(bmain, scene, view_layer, NULL, &stats_fmt)) { + if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) { get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt); } } @@ -731,7 +729,7 @@ static void stats_row(int col1, void ED_info_draw_stats( Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height) { - BLI_assert(v3d_local == NULL || v3d_local->localvd != NULL); + BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr); SceneStatsFmt stats_fmt; if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) { return; @@ -739,7 +737,7 @@ void ED_info_draw_stats( Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; const int font_id = BLF_set_default(); UI_FontThemeColor(font_id, TH_TEXT_HI); @@ -801,7 +799,7 @@ void ED_info_draw_stats( stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height); stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else if (obedit->type == OB_ARMATURE) { stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); @@ -816,15 +814,15 @@ void ED_info_draw_stats( stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } else if ((ob) && (ob->type == OB_GPENCIL)) { - stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height); - stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height); - stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height); - stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height); + stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height); + stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height); + stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height); + stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height); } else if (ob && (object_mode & OB_MODE_SCULPT)) { if (stats_is_object_dynamic_topology_sculpt(ob)) { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else { stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, stats_fmt.totvert, y, height); @@ -835,10 +833,10 @@ void ED_info_draw_stats( stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height); } else { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); - stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height); - stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height); + stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } BLF_disable(font_id, BLF_SHADOW); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 600309c2c86..e88d61fe880 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -44,17 +44,17 @@ set(SRC node_draw.cc node_edit.cc node_geometry_attribute_search.cc - node_gizmo.c + node_gizmo.cc node_group.cc - node_ops.c + node_ops.cc node_relationships.cc node_select.cc node_templates.cc node_toolbar.cc node_view.cc - space_node.c + space_node.cc - node_intern.h + node_intern.hh ) set(LIB diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 57fecba76f7..97fa93ab0bc 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -77,7 +77,7 @@ #include "NOD_node_declaration.hh" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ #define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME @@ -152,7 +152,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE); + uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } @@ -337,12 +337,13 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree, node->totr = rect; } -static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect) +static void node_draw_frame_label(bNodeTree *ntree, bNode *node, SpaceNode *snode) { + const float aspect = snode->runtime->aspect; /* XXX font id is crap design */ const int fontid = UI_style_get()->widgetlabel.uifont_id; NodeFrame *data = (NodeFrame *)node->storage; - const int font_size = data->label_size / aspect; + const float font_size = data->label_size / aspect; char label[MAX_NAME]; nodeLabel(ntree, node, label, sizeof(label)); @@ -350,7 +351,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp BLF_enable(fontid, BLF_ASPECT); BLF_aspect(fontid, aspect, aspect, 1.0f); /* clamp otherwise it can suck up a LOT of memory */ - BLF_size(fontid, MIN2(24, font_size), U.dpi); + BLF_size(fontid, MIN2(24.0f, font_size), U.dpi); /* title color */ int color_id = node_get_colorid(node); @@ -468,7 +469,9 @@ static void node_draw_frame(const bContext *C, } /* label and text */ - node_draw_frame_label(ntree, node, snode->runtime->aspect); + node_draw_frame_label(ntree, node, snode); + + node_draw_extra_info_panel(snode, node); UI_block_end(C, node->block); UI_block_draw(C, node->block); @@ -4399,7 +4402,10 @@ void node_draw_link_bezier(const bContext *C, } /* NOTE: this is used for fake links in groups too. */ -void node_draw_link(const bContext *C, View2D *v2d, SpaceNode *snode, bNodeLink *link) +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link) { int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE; diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index f84de363430..2e3579caaa1 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -56,7 +56,7 @@ #include "UI_view2d.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Utilities diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc index a0ff7f3ce25..2f3855fd654 100644 --- a/source/blender/editors/space_node/node_context_path.cc +++ b/source/blender/editors/space_node/node_context_path.cc @@ -43,7 +43,7 @@ #include "UI_interface.hh" -#include "node_intern.h" +#include "node_intern.hh" struct Mesh; struct Curve; diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index b6c24a55a78..1d62321cae3 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -85,7 +85,9 @@ #include "FN_field_cpp_type.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ + +#include <iomanip> #ifdef WITH_COMPOSITOR # include "COM_compositor.h" @@ -843,29 +845,43 @@ struct SocketTooltipData { bNodeSocket *socket; }; -static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, - std::stringstream &ss) +static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss) { auto id_to_inspection_string = [&](ID *id, short idcode) { ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")"; }; - const GPointer value = value_log.value(); const CPPType &type = *value.type(); + const void *buffer = value.get(); if (type.is<Object *>()) { - id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB); + id_to_inspection_string((ID *)buffer, ID_OB); } else if (type.is<Material *>()) { - id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA); + id_to_inspection_string((ID *)buffer, ID_MA); } else if (type.is<Tex *>()) { - id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE); + id_to_inspection_string((ID *)buffer, ID_TE); } else if (type.is<Image *>()) { - id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM); + id_to_inspection_string((ID *)buffer, ID_IM); } else if (type.is<Collection *>()) { - id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR); + id_to_inspection_string((ID *)buffer, ID_GR); + } + else if (type.is<int>()) { + ss << *(int *)buffer << TIP_(" (Integer)"); + } + else if (type.is<float>()) { + ss << *(float *)buffer << TIP_(" (Float)"); + } + else if (type.is<blender::float3>()) { + ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); + } + else if (type.is<bool>()) { + ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); + } + else if (type.is<std::string>()) { + ss << *(std::string *)buffer << TIP_(" (String)"); } } @@ -880,21 +896,7 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v if (field) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); blender::fn::evaluate_constant_field(field, buffer); - if (type.is<int>()) { - ss << *(int *)buffer << TIP_(" (Integer)"); - } - else if (type.is<float>()) { - ss << *(float *)buffer << TIP_(" (Float)"); - } - else if (type.is<blender::float3>()) { - ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); - } - else if (type.is<bool>()) { - ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); - } - else if (type.is<std::string>()) { - ss << *(std::string *)buffer << TIP_(" (String)"); - } + create_inspection_string_for_generic_value({type, buffer}, ss); type.destruct(buffer); } else { @@ -1023,7 +1025,7 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, std::stringstream ss; if (const geo_log::GenericValueLog *generic_value_log = dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { - create_inspection_string_for_generic_value(*generic_value_log, ss); + create_inspection_string_for_generic_value(generic_value_log->value(), ss); } if (const geo_log::GFieldValueLog *gfield_value_log = dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) { @@ -1107,21 +1109,8 @@ static void node_socket_draw_nested(const bContext *C, C, *data->ntree, *data->node, *data->socket); std::stringstream output; - if (data->node->declaration != nullptr) { - ListBase *list; - Span<blender::nodes::SocketDeclarationPtr> decl_list; - - if (data->socket->in_out == SOCK_IN) { - list = &data->node->inputs; - decl_list = data->node->declaration->inputs(); - } - else { - list = &data->node->outputs; - decl_list = data->node->declaration->outputs(); - } - - const int socket_index = BLI_findindex(list, data->socket); - const blender::nodes::SocketDeclaration &socket_decl = *decl_list[socket_index]; + if (data->socket->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *data->socket->declaration; blender::StringRef description = socket_decl.description(); if (!description.is_empty()) { output << TIP_(description.data()) << ".\n\n"; @@ -1590,6 +1579,235 @@ static void node_add_error_message_button( UI_block_emboss_set(node.block, UI_EMBOSS); } +static void get_exec_time_other_nodes(const bNode *node, + const SpaceNode *snode, + std::chrono::microseconds &exec_time, + int &node_count) +{ + if (node->type == NODE_GROUP) { + const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( + *snode); + if (root_tree_log == nullptr) { + return; + } + const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node->name); + if (tree_log == nullptr) { + return; + } + tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { + exec_time += node_log.execution_time(); + node_count++; + }); + } + else { + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( + *snode, *node); + if (node_log) { + exec_time += node_log->execution_time(); + node_count++; + } + } +} + +static std::chrono::microseconds node_get_execution_time(const bNodeTree *ntree, + const bNode *node, + const SpaceNode *snode, + int &node_count) +{ + std::chrono::microseconds exec_time = std::chrono::microseconds::zero(); + if (node->type == NODE_GROUP_OUTPUT) { + const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( + *snode); + + if (tree_log == nullptr) { + return exec_time; + } + tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { + exec_time += node_log.execution_time(); + node_count++; + }); + } + else if (node->type == NODE_FRAME) { + /* Could be cached in the future if this recursive code turns out to be slow. */ + LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { + if (tnode->parent != node) { + continue; + } + + if (tnode->type == NODE_FRAME) { + exec_time += node_get_execution_time(ntree, tnode, snode, node_count); + } + else { + get_exec_time_other_nodes(tnode, snode, exec_time, node_count); + } + } + } + else { + get_exec_time_other_nodes(node, snode, exec_time, node_count); + } + return exec_time; +} + +static std::string node_get_execution_time_label(const SpaceNode *snode, const bNode *node) +{ + int node_count = 0; + std::chrono::microseconds exec_time = node_get_execution_time( + snode->nodetree, node, snode, node_count); + + if (node_count == 0) { + return std::string(""); + } + + uint64_t exec_time_us = exec_time.count(); + + /* Don't show time if execution time is 0 microseconds. */ + if (exec_time_us == 0) { + return std::string("-"); + } + if (exec_time_us < 100) { + return std::string("< 0.1 ms"); + } + + int precision = 0; + /* Show decimal if value is below 1ms */ + if (exec_time_us < 1000) { + precision = 2; + } + else if (exec_time_us < 10000) { + precision = 1; + } + + std::stringstream stream; + stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f); + return stream.str() + " ms"; +} + +struct NodeExtraInfoRow { + std::string text; + const char *tooltip; + int icon; +}; + +static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode *snode, const bNode *node) +{ + Vector<NodeExtraInfoRow> rows; + if (!(snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) { + return rows; + } + + if (snode->overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode->edittree->type == NTREE_GEOMETRY && + (ELEM(node->typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) || + ELEM(node->type, NODE_FRAME, NODE_GROUP_OUTPUT))) { + NodeExtraInfoRow row; + row.text = node_get_execution_time_label(snode, node); + if (!row.text.empty()) { + row.tooltip = TIP_( + "The execution time from the node tree's latest evaluation. For frame and group nodes, " + "the time for all sub-nodes"); + row.icon = ICON_PREVIEW_RANGE; + rows.append(std::move(row)); + } + } + return rows; +} + +static void node_draw_extra_info_row(const bNode *node, + const rctf *rect, + const int row, + const NodeExtraInfoRow &extra_info_row) +{ + uiBut *but_timing = uiDefBut(node->block, + UI_BTYPE_LABEL, + 0, + extra_info_row.text.c_str(), + (int)(rect->xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f), + (int)(rect->ymin + row * (20.0f * U.dpi_fac)), + (short)(rect->xmax - rect->xmin), + (short)NODE_DY, + nullptr, + 0, + 0, + 0, + 0, + ""); + UI_block_emboss_set(node->block, UI_EMBOSS_NONE); + uiBut *but_icon = uiDefIconBut(node->block, + UI_BTYPE_BUT, + 0, + extra_info_row.icon, + (int)(rect->xmin + 6.0f * U.dpi_fac), + (int)(rect->ymin + row * (20.0f * U.dpi_fac)), + NODE_HEADER_ICON_SIZE * 0.8f, + UI_UNIT_Y, + nullptr, + 0, + 0, + 0, + 0, + extra_info_row.tooltip); + UI_block_emboss_set(node->block, UI_EMBOSS); + if (node->flag & NODE_MUTED) { + UI_but_flag_enable(but_timing, UI_BUT_INACTIVE); + UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); + } +} + +void node_draw_extra_info_panel(const SpaceNode *snode, const bNode *node) +{ + Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node); + + if (extra_info_rows.size() == 0) { + return; + } + + const rctf *rct = &node->totr; + float color[4]; + rctf extra_info_rect; + + if (node->type == NODE_FRAME) { + extra_info_rect.xmin = rct->xmin; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; + extra_info_rect.ymin = rct->ymin + 2.0f * U.dpi_fac; + extra_info_rect.ymax = rct->ymin + 2.0f * U.dpi_fac; + } + else { + extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; + extra_info_rect.ymin = rct->ymax; + extra_info_rect.ymax = rct->ymax + extra_info_rows.size() * (20.0f * U.dpi_fac); + + if (node->flag & NODE_MUTED) { + UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color); + } + else { + UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color); + } + color[3] -= 0.35f; + UI_draw_roundbox_corner_set( + UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & + ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); + UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color); + + /* Draw outline. */ + const float outline_width = 1.0f; + extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac - outline_width; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac + outline_width; + extra_info_rect.ymin = rct->ymax - outline_width; + extra_info_rect.ymax = rct->ymax + outline_width + + extra_info_rows.size() * (20.0f * U.dpi_fac); + + UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color); + UI_draw_roundbox_corner_set( + UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & + ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); + UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color); + } + + for (int row : extra_info_rows.index_range()) { + node_draw_extra_info_row(node, &extra_info_rect, row, extra_info_rows[row]); + } +} + static void node_draw_basis(const bContext *C, const View2D *v2d, const SpaceNode *snode, @@ -1615,6 +1833,8 @@ static void node_draw_basis(const bContext *C, GPU_line_width(1.0f); + node_draw_extra_info_panel(snode, node); + /* Header. */ { const rctf rect = { @@ -1855,7 +2075,13 @@ static void node_draw_basis(const bContext *C, UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline); } - node_draw_sockets(v2d, C, ntree, node, true, false); + float scale; + UI_view2d_scale_get(v2d, &scale, nullptr); + + /* Skip slow socket drawing if zoom is small. */ + if (scale > 0.2f) { + node_draw_sockets(v2d, C, ntree, node, true, false); + } /* Preview. */ bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data; @@ -2123,15 +2349,15 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode) } } /* Count temporary links going into this socket. */ - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) { int &count = counts.lookup_or_add(link->tosock, 0); count++; } } } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { if (socket->flag & SOCK_MULTI_INPUT) { @@ -2390,9 +2616,9 @@ void node_draw_space(const bContext *C, ARegion *region) /* Temporary links. */ GPU_blend(GPU_BLEND_ALPHA); GPU_line_smooth(true); - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data); + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { + node_draw_link(C, v2d, snode, link); } } GPU_line_smooth(false); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 030d1672a08..30c9f7ea56b 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -76,7 +76,7 @@ #include "NOD_geometry.h" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ #define USE_ESC_COMPO @@ -1192,7 +1192,7 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo } /* type is SOCK_IN and/or SOCK_OUT */ -int node_find_indicated_socket( +bool node_find_indicated_socket( SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out) { rctf rect; @@ -1224,7 +1224,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1232,7 +1232,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1245,7 +1245,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1253,7 +1253,7 @@ int node_find_indicated_socket( } } - return 0; + return false; } /* ****************** Link Dimming *********************** */ @@ -1775,8 +1775,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - /* Only allow muting of nodes having a mute func! */ - if ((node->flag & SELECT) && node->typeinfo->update_internal_links) { + if ((node->flag & SELECT) && !node->typeinfo->no_muting) { node->flag ^= NODE_MUTED; snode_update(snode, node); do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node)); diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 063e6348123..79ba9b8d2d9 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -44,7 +44,7 @@ #include "NOD_geometry_nodes_eval_log.hh" -#include "node_intern.h" +#include "node_intern.hh" using blender::IndexRange; using blender::Map; diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.cc index e1deca54890..717f4d2f4f9 100644 --- a/source/blender/editors/space_node/node_gizmo.c +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -18,7 +18,7 @@ * \ingroup spnode */ -#include <math.h> +#include <cmath> #include "BLI_math_matrix.h" #include "BLI_math_vector.h" @@ -41,7 +41,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" +#include "node_intern.hh" /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -80,9 +80,9 @@ static void gizmo_node_backdrop_prop_matrix_get(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - const SpaceNode *snode = gz_prop->custom_func.user_data; + const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data; matrix[0][0] = snode->zoom; matrix[1][1] = snode->zoom; matrix[3][0] = snode->xof; @@ -93,9 +93,9 @@ static void gizmo_node_backdrop_prop_matrix_set(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - SpaceNode *snode = gz_prop->custom_func.user_data; + SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data; snode->zoom = matrix[0][0]; snode->xof = matrix[3][0]; snode->yof = matrix[3][1]; @@ -122,9 +122,9 @@ static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + wmGizmoWrapper *wwrapper = (wmGizmoWrapper *)MEM_mallocN(sizeof(wmGizmoWrapper), __func__); - wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(wwrapper->gizmo->ptr, "transform", @@ -139,11 +139,11 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo; const ARegion *region = CTX_wm_region(C); /* center is always at the origin */ - const float origin[3] = {region->winx / 2, region->winy / 2}; + const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f}; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { const float dims[2] = { @@ -164,14 +164,12 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1); #endif - WM_gizmo_target_property_def_func(cage, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_backdrop_prop_matrix_get, - .value_set_fn = gizmo_node_backdrop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = snode, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_backdrop_prop_matrix_get; + params.value_set_fn = gizmo_node_backdrop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(cage, "matrix", ¶ms); } else { WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, true); @@ -262,12 +260,12 @@ static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - const bNode *node = gz_prop->custom_func.user_data; - const NodeTwoXYs *nxy = node->storage; + const bNode *node = (const bNode *)gz_prop->custom_func.user_data; + const NodeTwoXYs *nxy = (const NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -281,12 +279,12 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - bNode *node = gz_prop->custom_func.user_data; - NodeTwoXYs *nxy = node->storage; + bNode *node = (bNode *)gz_prop->custom_func.user_data; + NodeTwoXYs *nxy = (NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -294,15 +292,8 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, const bool ny = rct.ymin > rct.ymax; BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1])); BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); - BLI_rctf_isect( - &(rctf){ - .xmin = 0, - .ymin = 0, - .xmax = 1, - .ymax = 1, - }, - &rct, - &rct); + const rctf rct_isect{0, 0, 1, 1}; + BLI_rctf_isect(&rct_isect, &rct, &rct); if (nx) { SWAP(float, rct.xmin, rct.xmax); } @@ -337,10 +328,10 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), - __func__); + struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN( + sizeof(struct NodeCropWidgetGroup), __func__); - crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(crop_group->border->ptr, "transform", @@ -352,7 +343,7 @@ static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -362,12 +353,12 @@ static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup * static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCropWidgetGroup *crop_group = gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gzgroup->customdata; wmGizmo *gz = crop_group->border; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -385,14 +376,12 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative"); - WM_gizmo_target_property_def_func(gz, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_crop_prop_matrix_get, - .value_set_fn = gizmo_node_crop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = node, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_crop_prop_matrix_get; + params.value_set_fn = gizmo_node_crop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(gz, "matrix", ¶ms); } else { WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); @@ -450,10 +439,10 @@ static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmGizmoGroupType *UNU static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), - __func__); + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)MEM_mallocN( + sizeof(NodeSunBeamsWidgetGroup), __func__); - sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL); + sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr); wmGizmo *gz = sbeam_group->gizmo; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -465,9 +454,9 @@ static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -478,12 +467,12 @@ static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; wmGizmo *gz = sbeam_group->gizmo; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -555,12 +544,12 @@ static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN( - sizeof(struct NodeCornerPinWidgetGroup), __func__); + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)MEM_mallocN( + sizeof(NodeCornerPinWidgetGroup), __func__); const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false); for (int i = 0; i < 4; i++) { - cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, NULL); + cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr); wmGizmo *gz = cpin_group->gizmos[i]; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -573,7 +562,7 @@ static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmo static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -591,11 +580,11 @@ static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoG static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -606,7 +595,7 @@ static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup /* need to set property here for undo. TODO: would prefer to do this in _init. */ int i = 0; - for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { + for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) { if (sock->type == SOCK_VECTOR) { wmGizmo *gz = cpin_group->gizmos[i++]; diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index d7541d8f512..d9fbbc81a8f 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -58,7 +58,7 @@ #include "NOD_common.h" #include "NOD_socket.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Local Utilities diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h deleted file mode 100644 index 383fe5afdf9..00000000000 --- a/source/blender/editors/space_node/node_intern.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - */ - -#pragma once - -#include "BKE_node.h" -#include "UI_interface.h" -#include "UI_view2d.h" -#include <stddef.h> /* for size_t */ - -/* internal exports only */ - -struct ARegion; -struct ARegionType; -struct Main; -struct NodeInsertOfsData; -struct View2D; -struct bContext; -struct bNode; -struct bNodeLink; -struct bNodeSocket; -struct wmGizmoGroupType; -struct wmKeyConfig; -struct wmWindow; - -#ifdef __cplusplus -extern "C" { -#endif - -/* temp data to pass on to modal */ -typedef struct bNodeLinkDrag { - struct bNodeLinkDrag *next, *prev; - - /* List of links dragged by the operator. - * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks. - * This way the links can be added to the node tree while being stored in this list. - */ - ListBase links; - bool from_multi_input_socket; - int in_out; - - /** Temporarily stores the last picked link from multi-input socket operator. */ - struct bNodeLink *last_picked_multi_input_socket_link; - - /** Temporarily stores the last hovered socket for multi-input socket operator. - * Store it to recalculate sorting after it is no longer hovered. */ - struct bNode *last_node_hovered_while_dragging_a_link; - - /* Data for edge panning */ - View2DEdgePanData pan_data; -} bNodeLinkDrag; - -typedef struct SpaceNode_Runtime { - float aspect; - - /** Mouse position for drawing socket-less links and adding nodes. */ - float cursor[2]; - - /** For auto compositing. */ - bool recalc; - - /** Temporary data for modal linking operator. */ - struct ListBase linkdrag; - - /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ - /** Temporary data for node insert offset (in UI called Auto-offset). */ - struct NodeInsertOfsData *iofsd; -} SpaceNode_Runtime; - -/* space_node.c */ - -/* transform between View2Ds in the tree path */ -void space_node_group_offset(struct SpaceNode *snode, float *x, float *y); - -/* node_draw.cc */ -float node_socket_calculate_height(const bNodeSocket *socket); -void node_link_calculate_multi_input_position(const float socket_x, - const float socket_y, - const int index, - const int total_inputs, - float r[2]); - -int node_get_colorid(struct bNode *node); -int node_get_resize_cursor(int directions); -void node_draw_shadow(const struct SpaceNode *snode, - const struct bNode *node, - float radius, - float alpha); -void node_draw_default(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - struct bNode *node, - bNodeInstanceKey key); -void node_draw_sockets(const struct View2D *v2d, - const struct bContext *C, - struct bNodeTree *ntree, - struct bNode *node, - bool draw_outputs, - bool select_all); -void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); -int node_select_area_default(struct bNode *node, int x, int y); -int node_tweak_area_default(struct bNode *node, int x, int y); -void node_socket_color_get(const struct bContext *C, - struct bNodeTree *ntree, - struct PointerRNA *node_ptr, - struct bNodeSocket *sock, - float r_color[4]); -void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree); -void node_draw_nodetree(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - bNodeInstanceKey parent_key); -void node_draw_space(const bContext *C, ARegion *region); - -void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]); -/* DPI scaled coords */ -void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry); -void node_to_updated_rect(const struct bNode *node, rctf *r_rect); -void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry); - -/* node_toolbar.c */ -void node_toolbar_register(struct ARegionType *art); - -/* node_ops.c */ -void node_operatortypes(void); -void node_keymap(struct wmKeyConfig *keyconf); - -/* node_select.c */ -void node_deselect_all(struct SpaceNode *snode); -void node_socket_select(struct bNode *node, struct bNodeSocket *sock); -void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, const bool deselect_node); -void node_deselect_all_input_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_deselect_all_output_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_select_single(struct bContext *C, struct bNode *node); - -void NODE_OT_select(struct wmOperatorType *ot); -void NODE_OT_select_all(struct wmOperatorType *ot); -void NODE_OT_select_linked_to(struct wmOperatorType *ot); -void NODE_OT_select_linked_from(struct wmOperatorType *ot); -void NODE_OT_select_box(struct wmOperatorType *ot); -void NODE_OT_select_circle(struct wmOperatorType *ot); -void NODE_OT_select_lasso(struct wmOperatorType *ot); -void NODE_OT_select_grouped(struct wmOperatorType *ot); -void NODE_OT_select_same_type_step(struct wmOperatorType *ot); -void NODE_OT_find_node(struct wmOperatorType *ot); - -/* node_view.c */ -int space_node_view_flag(struct bContext *C, - struct SpaceNode *snode, - ARegion *region, - const int node_flag, - const int smooth_viewtx); - -void NODE_OT_view_all(struct wmOperatorType *ot); -void NODE_OT_view_selected(struct wmOperatorType *ot); -void NODE_OT_geometry_node_view_legacy(struct wmOperatorType *ot); - -void NODE_OT_backimage_move(struct wmOperatorType *ot); -void NODE_OT_backimage_zoom(struct wmOperatorType *ot); -void NODE_OT_backimage_fit(struct wmOperatorType *ot); -void NODE_OT_backimage_sample(struct wmOperatorType *ot); - -/* drawnode.c */ -void nodelink_batch_start(struct SpaceNode *snode); -void nodelink_batch_end(struct SpaceNode *snode); - -void node_draw_link(const struct bContext *C, - struct View2D *v2d, - struct SpaceNode *snode, - struct bNodeLink *link); -void node_draw_link_bezier(const struct bContext *C, - const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - int th_col1, - int th_col2, - int th_col3); -bool node_link_bezier_points(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float coord_array[][2], - const int resol); -bool node_link_bezier_handles(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float vec[4][2]); -void draw_nodespace_back_pix(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - bNodeInstanceKey parent_key); - -/* node_add.c */ -bNode *node_add_node( - const struct bContext *C, const char *idname, int type, float locx, float locy); -void NODE_OT_add_reroute(struct wmOperatorType *ot); -void NODE_OT_add_group(struct wmOperatorType *ot); -void NODE_OT_add_object(struct wmOperatorType *ot); -void NODE_OT_add_collection(struct wmOperatorType *ot); -void NODE_OT_add_texture(struct wmOperatorType *ot); -void NODE_OT_add_file(struct wmOperatorType *ot); -void NODE_OT_add_mask(struct wmOperatorType *ot); -void NODE_OT_new_node_tree(struct wmOperatorType *ot); - -/* node_group.c */ -const char *node_group_idname(struct bContext *C); -void NODE_OT_group_make(struct wmOperatorType *ot); -void NODE_OT_group_insert(struct wmOperatorType *ot); -void NODE_OT_group_ungroup(struct wmOperatorType *ot); -void NODE_OT_group_separate(struct wmOperatorType *ot); -void NODE_OT_group_edit(struct wmOperatorType *ot); - -/* node_relationships.c */ -void sort_multi_input_socket_links(struct SpaceNode *snode, - struct bNode *node, - struct bNodeLink *drag_link, - float cursor[2]); -bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); - -void NODE_OT_link(struct wmOperatorType *ot); -void NODE_OT_link_make(struct wmOperatorType *ot); -void NODE_OT_links_cut(struct wmOperatorType *ot); -void NODE_OT_links_detach(struct wmOperatorType *ot); -void NODE_OT_links_mute(struct wmOperatorType *ot); - -void NODE_OT_parent_set(struct wmOperatorType *ot); -void NODE_OT_join(struct wmOperatorType *ot); -void NODE_OT_attach(struct wmOperatorType *ot); -void NODE_OT_detach(struct wmOperatorType *ot); - -void NODE_OT_link_viewer(struct wmOperatorType *ot); - -void NODE_OT_insert_offset(struct wmOperatorType *ot); - -/* node_edit.c */ -void snode_notify(struct bContext *C, struct SpaceNode *snode); -void snode_dag_update(struct bContext *C, struct SpaceNode *snode); -void snode_set_context(const struct bContext *C); - -void snode_update(struct SpaceNode *snode, struct bNode *node); -bool composite_node_active(struct bContext *C); -bool composite_node_editable(struct bContext *C); - -bool node_has_hidden_sockets(struct bNode *node); -void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set); -int node_render_changed_exec(bContext *, struct wmOperator *); -int node_find_indicated_socket(struct SpaceNode *snode, - struct bNode **nodep, - struct bNodeSocket **sockp, - const float cursor[2], - int in_out); -float node_link_dim_factor(const struct View2D *v2d, const struct bNodeLink *link); -bool node_link_is_hidden_or_dimmed(const struct View2D *v2d, const struct bNodeLink *link); - -void NODE_OT_duplicate(struct wmOperatorType *ot); -void NODE_OT_delete(struct wmOperatorType *ot); -void NODE_OT_delete_reconnect(struct wmOperatorType *ot); -void NODE_OT_resize(struct wmOperatorType *ot); - -void NODE_OT_mute_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot); -void NODE_OT_preview_toggle(struct wmOperatorType *ot); -void NODE_OT_options_toggle(struct wmOperatorType *ot); -void NODE_OT_node_copy_color(struct wmOperatorType *ot); - -void NODE_OT_read_viewlayers(struct wmOperatorType *ot); -void NODE_OT_render_changed(struct wmOperatorType *ot); - -void NODE_OT_output_file_add_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot); - -void NODE_OT_switch_view_update(struct wmOperatorType *ot); - -/* NOTE: clipboard_cut is a simple macro of copy + delete. */ -void NODE_OT_clipboard_copy(struct wmOperatorType *ot); -void NODE_OT_clipboard_paste(struct wmOperatorType *ot); - -void NODE_OT_tree_socket_add(struct wmOperatorType *ot); -void NODE_OT_tree_socket_remove(struct wmOperatorType *ot); -void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot); -void NODE_OT_tree_socket_move(struct wmOperatorType *ot); - -void NODE_OT_shader_script_update(struct wmOperatorType *ot); - -void NODE_OT_viewer_border(struct wmOperatorType *ot); -void NODE_OT_clear_viewer_border(struct wmOperatorType *ot); - -/* node_widgets.c */ -void NODE_GGT_backdrop_transform(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt); - -void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot); -void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot); - -/* node_geometry_attribute_search.cc */ -void node_geometry_add_attribute_search_button(const struct bContext *C, - const struct bNodeTree *node_tree, - const struct bNode *node, - struct PointerRNA *socket_ptr, - struct uiLayout *layout); - -extern const char *node_context_dir[]; - -/* XXXXXX */ - -/* Nodes draw without dpi - the view zoom is flexible. */ -#define HIDDEN_RAD (0.75f * U.widget_unit) -#define BASIS_RAD (0.2f * U.widget_unit) -#define NODE_DYS (U.widget_unit / 2) -#define NODE_DY U.widget_unit -#define NODE_SOCKDY (0.1f * U.widget_unit) -#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) -#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) -#define NODE_MARGIN_X (1.2f * U.widget_unit) -#define NODE_SOCKSIZE (0.25f * U.widget_unit) -#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) -#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) -#define NODE_LINK_RESOL 12 - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -# include "BLI_vector.hh" -# include "UI_interface.hh" -namespace blender::ed::space_node { -Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); -} -#endif diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh new file mode 100644 index 00000000000..6dc57c1fb79 --- /dev/null +++ b/source/blender/editors/space_node/node_intern.hh @@ -0,0 +1,333 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spnode + */ + +#pragma once + +#include "BKE_node.h" +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BLI_vector.hh" +#include "UI_interface.hh" + +#include <stddef.h> /* for size_t */ + +/* internal exports only */ + +struct ARegion; +struct ARegionType; +struct Main; +struct NodeInsertOfsData; +struct View2D; +struct bContext; +struct bNode; +struct bNodeLink; +struct bNodeSocket; +struct wmGizmoGroupType; +struct wmKeyConfig; +struct wmWindow; + +/* temp data to pass on to modal */ +struct bNodeLinkDrag { + /** Links dragged by the operator. */ + blender::Vector<bNodeLink *> links; + bool from_multi_input_socket; + int in_out; + + /** Temporarily stores the last picked link from multi-input socket operator. */ + struct bNodeLink *last_picked_multi_input_socket_link; + + /** Temporarily stores the last hovered socket for multi-input socket operator. + * Store it to recalculate sorting after it is no longer hovered. */ + struct bNode *last_node_hovered_while_dragging_a_link; + + /* Data for edge panning */ + View2DEdgePanData pan_data; +}; + +struct SpaceNode_Runtime { + float aspect; + + /** Mouse position for drawing socket-less links and adding nodes. */ + float cursor[2]; + + /** For auto compositing. */ + bool recalc; + + /** Temporary data for modal linking operator. */ + std::unique_ptr<bNodeLinkDrag> linkdrag; + + /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ + /** Temporary data for node insert offset (in UI called Auto-offset). */ + struct NodeInsertOfsData *iofsd; +}; + +/* space_node.c */ + +/* transform between View2Ds in the tree path */ +void space_node_group_offset(SpaceNode *snode, float *x, float *y); + +/* node_draw.cc */ +float node_socket_calculate_height(const bNodeSocket *socket); +void node_link_calculate_multi_input_position(const float socket_x, + const float socket_y, + const int index, + const int total_inputs, + float r[2]); + +int node_get_colorid(bNode *node); +void node_draw_extra_info_panel(const SpaceNode *snode, const bNode *node); +int node_get_resize_cursor(int directions); +void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha); +void node_draw_default(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNode *node, + bNodeInstanceKey key); +void node_draw_sockets(const View2D *v2d, + const bContext *C, + bNodeTree *ntree, + bNode *node, + bool draw_outputs, + bool select_all); +void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node); +int node_select_area_default(bNode *node, int x, int y); +int node_tweak_area_default(bNode *node, int x, int y); +void node_socket_color_get(const bContext *C, + bNodeTree *ntree, + PointerRNA *node_ptr, + bNodeSocket *sock, + float r_color[4]); +void node_update_nodetree(const bContext *C, bNodeTree *ntree); +void node_draw_nodetree(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNodeInstanceKey parent_key); +void node_draw_space(const bContext *C, ARegion *region); + +void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]); +/* DPI scaled coords */ +void node_to_view(const bNode *node, float x, float y, float *rx, float *ry); +void node_to_updated_rect(const bNode *node, rctf *r_rect); +void node_from_view(const bNode *node, float x, float y, float *rx, float *ry); + +/* node_toolbar.c */ +void node_toolbar_register(ARegionType *art); + +/* node_ops.c */ +void node_operatortypes(void); +void node_keymap(wmKeyConfig *keyconf); + +/* node_select.c */ +void node_deselect_all(SpaceNode *snode); +void node_socket_select(bNode *node, bNodeSocket *sock); +void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node); +void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_select_single(bContext *C, bNode *node); + +void NODE_OT_select(wmOperatorType *ot); +void NODE_OT_select_all(wmOperatorType *ot); +void NODE_OT_select_linked_to(wmOperatorType *ot); +void NODE_OT_select_linked_from(wmOperatorType *ot); +void NODE_OT_select_box(wmOperatorType *ot); +void NODE_OT_select_circle(wmOperatorType *ot); +void NODE_OT_select_lasso(wmOperatorType *ot); +void NODE_OT_select_grouped(wmOperatorType *ot); +void NODE_OT_select_same_type_step(wmOperatorType *ot); +void NODE_OT_find_node(wmOperatorType *ot); + +/* node_view.c */ +int space_node_view_flag( + bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx); + +void NODE_OT_view_all(wmOperatorType *ot); +void NODE_OT_view_selected(wmOperatorType *ot); +void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot); + +void NODE_OT_backimage_move(wmOperatorType *ot); +void NODE_OT_backimage_zoom(wmOperatorType *ot); +void NODE_OT_backimage_fit(wmOperatorType *ot); +void NODE_OT_backimage_sample(wmOperatorType *ot); + +/* drawnode.c */ +void nodelink_batch_start(SpaceNode *snode); +void nodelink_batch_end(SpaceNode *snode); + +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link); +void node_draw_link_bezier(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + int th_col1, + int th_col2, + int th_col3); +bool node_link_bezier_points(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float coord_array[][2], + const int resol); +bool node_link_bezier_handles(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float vec[4][2]); +void draw_nodespace_back_pix(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeInstanceKey parent_key); + +/* node_add.c */ +bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy); +void NODE_OT_add_reroute(wmOperatorType *ot); +void NODE_OT_add_group(wmOperatorType *ot); +void NODE_OT_add_object(wmOperatorType *ot); +void NODE_OT_add_collection(wmOperatorType *ot); +void NODE_OT_add_texture(wmOperatorType *ot); +void NODE_OT_add_file(wmOperatorType *ot); +void NODE_OT_add_mask(wmOperatorType *ot); +void NODE_OT_new_node_tree(wmOperatorType *ot); + +/* node_group.c */ +const char *node_group_idname(bContext *C); +void NODE_OT_group_make(wmOperatorType *ot); +void NODE_OT_group_insert(wmOperatorType *ot); +void NODE_OT_group_ungroup(wmOperatorType *ot); +void NODE_OT_group_separate(wmOperatorType *ot); +void NODE_OT_group_edit(wmOperatorType *ot); + +/* node_relationships.c */ +void sort_multi_input_socket_links(SpaceNode *snode, + bNode *node, + bNodeLink *drag_link, + float cursor[2]); +bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node); + +void NODE_OT_link(wmOperatorType *ot); +void NODE_OT_link_make(wmOperatorType *ot); +void NODE_OT_links_cut(wmOperatorType *ot); +void NODE_OT_links_detach(wmOperatorType *ot); +void NODE_OT_links_mute(wmOperatorType *ot); + +void NODE_OT_parent_set(wmOperatorType *ot); +void NODE_OT_join(wmOperatorType *ot); +void NODE_OT_attach(wmOperatorType *ot); +void NODE_OT_detach(wmOperatorType *ot); + +void NODE_OT_link_viewer(wmOperatorType *ot); + +void NODE_OT_insert_offset(wmOperatorType *ot); + +/* node_edit.c */ +void snode_notify(bContext *C, SpaceNode *snode); +void snode_dag_update(bContext *C, SpaceNode *snode); +void snode_set_context(const bContext *C); + +void snode_update(SpaceNode *snode, bNode *node); +bool composite_node_active(bContext *C); +bool composite_node_editable(bContext *C); + +bool node_has_hidden_sockets(bNode *node); +void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); +int node_render_changed_exec(bContext *, wmOperator *); +bool node_find_indicated_socket( + SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out); +float node_link_dim_factor(const View2D *v2d, const bNodeLink *link); +bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link); + +void NODE_OT_duplicate(wmOperatorType *ot); +void NODE_OT_delete(wmOperatorType *ot); +void NODE_OT_delete_reconnect(wmOperatorType *ot); +void NODE_OT_resize(wmOperatorType *ot); + +void NODE_OT_mute_toggle(wmOperatorType *ot); +void NODE_OT_hide_toggle(wmOperatorType *ot); +void NODE_OT_hide_socket_toggle(wmOperatorType *ot); +void NODE_OT_preview_toggle(wmOperatorType *ot); +void NODE_OT_options_toggle(wmOperatorType *ot); +void NODE_OT_node_copy_color(wmOperatorType *ot); + +void NODE_OT_read_viewlayers(wmOperatorType *ot); +void NODE_OT_render_changed(wmOperatorType *ot); + +void NODE_OT_output_file_add_socket(wmOperatorType *ot); +void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot); +void NODE_OT_output_file_move_active_socket(wmOperatorType *ot); + +void NODE_OT_switch_view_update(wmOperatorType *ot); + +/* NOTE: clipboard_cut is a simple macro of copy + delete. */ +void NODE_OT_clipboard_copy(wmOperatorType *ot); +void NODE_OT_clipboard_paste(wmOperatorType *ot); + +void NODE_OT_tree_socket_add(wmOperatorType *ot); +void NODE_OT_tree_socket_remove(wmOperatorType *ot); +void NODE_OT_tree_socket_change_type(wmOperatorType *ot); +void NODE_OT_tree_socket_move(wmOperatorType *ot); + +void NODE_OT_shader_script_update(wmOperatorType *ot); + +void NODE_OT_viewer_border(wmOperatorType *ot); +void NODE_OT_clear_viewer_border(wmOperatorType *ot); + +/* node_widgets.c */ +void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt); + +void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot); +void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot); + +/* node_geometry_attribute_search.cc */ +void node_geometry_add_attribute_search_button(const bContext *C, + const bNodeTree *node_tree, + const bNode *node, + PointerRNA *socket_ptr, + uiLayout *layout); + +extern const char *node_context_dir[]; + +/* XXXXXX */ + +/* Nodes draw without dpi - the view zoom is flexible. */ +#define HIDDEN_RAD (0.75f * U.widget_unit) +#define BASIS_RAD (0.2f * U.widget_unit) +#define NODE_DYS (U.widget_unit / 2) +#define NODE_DY U.widget_unit +#define NODE_SOCKDY (0.1f * U.widget_unit) +#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) +#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) +#define NODE_MARGIN_X (1.2f * U.widget_unit) +#define NODE_SOCKSIZE (0.25f * U.widget_unit) +#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) +#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) +#define NODE_LINK_RESOL 12 + +namespace blender::ed::space_node { +Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); +} diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.cc index 0c54da65e9c..4c08f4d7b47 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.cc @@ -33,9 +33,9 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ -void node_operatortypes(void) +void node_operatortypes() { WM_operatortype_append(NODE_OT_select); WM_operatortype_append(NODE_OT_select_all); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 55b547d3195..aee749edbc4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -60,9 +60,10 @@ #include "NOD_node_declaration.hh" #include "NOD_node_tree_ref.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using namespace blender::nodes::node_tree_ref_types; +using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Relations Helpers @@ -207,11 +208,9 @@ static void clear_picking_highlight(ListBase *links) } } -static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) +static bNodeLink *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; if (sock->in_out == SOCK_OUT) { oplink->fromnode = node; oplink->fromsock = sock; @@ -226,7 +225,7 @@ static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bN oplink->flag |= NODE_LINK_TEST; } oplink->flag |= NODE_LINK_DRAGGED; - return linkdata; + return oplink; } static void pick_link(const bContext *C, @@ -240,10 +239,9 @@ static void pick_link(const bContext *C, RNA_boolean_set(op->ptr, "has_link_picked", true); Main *bmain = CTX_data_main(C); - LinkData *linkdata = create_drag_link( - bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); + bNodeLink *link = create_drag_link(bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(link); nodeRemLink(snode->edittree, link_to_pick); BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr); @@ -324,19 +322,6 @@ static void pick_input_link_by_link_intersect(const bContext *C, } } -static int sort_nodes_locx(const void *a, const void *b) -{ - const bNodeListItem *nli1 = (const bNodeListItem *)a; - const bNodeListItem *nli2 = (const bNodeListItem *)b; - const bNode *node1 = nli1->node; - const bNode *node2 = nli2->node; - - if (node1->locx > node2->locx) { - return 1; - } - return 0; -} - static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used) { if (nodeSocketIsHidden(sock)) { @@ -527,30 +512,25 @@ static void snode_autoconnect(Main *bmain, const bool replace) { bNodeTree *ntree = snode->edittree; - ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list"); + Vector<bNode *> sorted_nodes; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & NODE_SELECT) { - bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem), - "temporary node list item"); - nli->node = node; - BLI_addtail(nodelist, nli); + sorted_nodes.append(node); } } - /* sort nodes left to right */ - BLI_listbase_sort(nodelist, sort_nodes_locx); + /* Sort nodes left to right. */ + std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) { + return a->locx < b->locx; + }); int numlinks = 0; - LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) { + for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) { bool has_selected_inputs = false; - if (nli->next == nullptr) { - break; - } - - bNode *node_fr = nli->node; - bNode *node_to = nli->next->node; + bNode *node_fr = sorted_nodes[i]; + bNode *node_to = sorted_nodes[i + 1]; /* corner case: input/output node aligned the wrong way around (T47729) */ if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) { SWAP(bNode *, node_fr, node_to); @@ -606,9 +586,6 @@ static void snode_autoconnect(Main *bmain, if (numlinks > 0) { ntreeUpdateTree(bmain, ntree); } - - BLI_freelistN(nodelist); - MEM_freeN(nodelist); } /** \} */ @@ -1013,9 +990,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) /* avoid updates while applying links */ ntree->is_updating = true; - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* See note below, but basically TEST flag means that the link * was connected to output (or to a node which affects the * output). @@ -1068,10 +1043,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); } - BLI_remlink(&snode->runtime->linkdrag, nldrag); - /* links->data pointers are either held by the tree or freed already */ - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); } static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) @@ -1083,9 +1055,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if socket is on the same node as the fromsock */ if (tnode && link->fromnode == tnode) { continue; @@ -1115,8 +1085,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + for (bNodeLink *link : nldrag->links) { if (nldrag->last_node_hovered_while_dragging_a_link) { sort_multi_input_socket_links( snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor); @@ -1130,9 +1099,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if this is already the target socket */ if (link->fromsock == tsock) { continue; @@ -1148,9 +1115,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { link->fromnode = nullptr; link->fromsock = nullptr; } @@ -1202,16 +1167,16 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -/* return 1 when socket clicked */ -static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach) +static std::unique_ptr<bNodeLinkDrag> node_link_init(Main *bmain, + SpaceNode *snode, + float cursor[2], + bool detach) { - bNodeLinkDrag *nldrag = nullptr; - /* output indicated? */ bNode *node; bNodeSocket *sock; if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); const int num_links = nodeCountSocketLinks(snode->edittree, sock); int link_limit = nodeSocketLinkLimit(sock); @@ -1221,9 +1186,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* detach current links and store them in the operator data */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { if (link->fromsock == sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1240,7 +1203,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link); } } @@ -1249,14 +1212,14 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } + /* or an input? */ - else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); nldrag->last_node_hovered_while_dragging_a_link = node; const int num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -1275,9 +1238,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor } if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link_to_pick; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1287,7 +1248,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link_to_pick); /* send changed event to original link->tonode */ @@ -1300,13 +1261,12 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } - return nldrag; + return {}; } static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1324,13 +1284,13 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach); + std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); if (nldrag) { UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); - op->customdata = nldrag; - BLI_addtail(&snode->runtime->linkdrag, nldrag); + snode->runtime->linkdrag = std::move(nldrag); + op->customdata = snode->runtime->linkdrag.get(); /* add modal handler */ WM_event_add_modal_handler(C, op); @@ -1345,12 +1305,10 @@ static void node_link_cancel(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; - BLI_remlink(&snode->runtime->linkdrag, nldrag); - UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); + clear_picking_highlight(&snode->edittree->links); } @@ -2369,8 +2327,8 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, /* NODE_TEST will be used later, so disable for all nodes */ ntreeNodeFlagSet(ntree, NODE_TEST, false); - /* insert->totr isn't updated yet, - * so totr_insert is used to get the correct worldspace coords */ + /* `insert->totr` isn't updated yet, + * so `totr_insert` is used to get the correct world-space coords. */ rctf totr_insert; node_to_updated_rect(insert, &totr_insert); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 29b8372d043..3c7b404547b 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -61,7 +61,7 @@ #include "MEM_guardedalloc.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /** * Function to detect if there is a visible view3d that uses workbench in texture mode. diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index f68d8589624..b2a7c1753fb 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -48,7 +48,7 @@ #include "UI_interface.h" #include "ED_node.h" /* own include */ -#include "node_intern.h" +#include "node_intern.hh" #include "ED_undo.h" diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_node/node_toolbar.cc index 2e7d6ab6cd5..c32dcbef91b 100644 --- a/source/blender/editors/space_node/node_toolbar.cc +++ b/source/blender/editors/space_node/node_toolbar.cc @@ -30,7 +30,7 @@ #include "WM_api.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************* node toolbar registration ************** */ diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index 762b4b36a39..36b84bec7eb 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -54,7 +54,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using blender::StringRef; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.cc index 888aeb08334..ac64503cfc9 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.cc @@ -52,21 +52,19 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************** tree path ********************* */ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) { - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; + LISTBASE_FOREACH_MUTABLE (bNodeTreePath *, path, &snode->treepath) { MEM_freeN(path); } BLI_listbase_clear(&snode->treepath); if (ntree) { - path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); path->nodetree = ntree; path->parent_key = NODE_INSTANCE_KEY_BASE; @@ -94,13 +92,13 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) { - bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); - bNodeTreePath *prev_path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last; path->nodetree = ntree; if (gnode) { if (prev_path) { @@ -129,12 +127,12 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_pop(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* don't remove root */ if (path == snode->treepath.first) { @@ -145,13 +143,13 @@ void ED_node_tree_pop(SpaceNode *snode) MEM_freeN(path); /* update current tree */ - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; ED_node_set_active_viewer_key(snode); /* listener updates the View2D center from edittree */ - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } int ED_node_tree_depth(SpaceNode *snode) @@ -163,12 +161,12 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level) { bNodeTreePath *path; int i; - for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) { + for (path = (bNodeTreePath *)snode->treepath.last, i = 0; path; path = path->prev, i++) { if (i == level) { return path->nodetree; } } - return NULL; + return nullptr; } int ED_node_tree_path_length(SpaceNode *snode) @@ -203,7 +201,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value) void ED_node_set_active_viewer_key(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (snode->nodetree && path) { snode->nodetree->active_viewer_key = path->parent_key; } @@ -211,7 +209,7 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) void space_node_group_offset(SpaceNode *snode, float *x, float *y) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (path && path->prev) { float dcenter[2]; @@ -228,10 +226,7 @@ void space_node_group_offset(SpaceNode *snode, float *x, float *y) static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - ARegion *region; - SpaceNode *snode; - - snode = MEM_callocN(sizeof(SpaceNode), "initnode"); + SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode"); snode->spacetype = SPACE_NODE; snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA; @@ -249,21 +244,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s NODE_TREE_TYPES_END; /* header */ - region = MEM_callocN(sizeof(ARegion), "header for node"); + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* buttons/list view */ - region = MEM_callocN(sizeof(ARegion), "buttons for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; /* toolbar */ - region = MEM_callocN(sizeof(ARegion), "node tools"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_TOOLS; @@ -272,7 +267,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->flag = RGN_FLAG_HIDDEN; /* main region */ - region = MEM_callocN(sizeof(ARegion), "main region for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -290,7 +285,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->v2d.max[0] = 32000.0f; region->v2d.max[1] = 32000.0f; - region->v2d.minzoom = 0.09f; + region->v2d.minzoom = 0.05f; region->v2d.maxzoom = 2.31f; region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); @@ -308,7 +303,10 @@ static void node_free(SpaceLink *sl) MEM_freeN(path); } - MEM_SAFE_FREE(snode->runtime); + if (snode->runtime) { + snode->runtime->linkdrag.reset(); + MEM_freeN(snode->runtime); + } } /* spacetype; init callback */ @@ -316,8 +314,8 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; - if (snode->runtime == NULL) { - snode->runtime = MEM_callocN(sizeof(SpaceNode_Runtime), __func__); + if (snode->runtime == nullptr) { + snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__); } } @@ -327,7 +325,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) wmNotifier *wmn = params->notifier; /* NOTE: #ED_area_tag_refresh will re-execute compositor. */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */ short shader_type = snode->shaderfrom; @@ -337,7 +335,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) switch (wmn->data) { case ND_NODES: { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* shift view to node tree center */ if (region && path) { UI_view2d_center_set(®ion->v2d, path->view_center[0], path->view_center[1]); @@ -379,7 +377,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) ED_area_tag_refresh(area); } else if (wmn->action == NA_ADDED && snode->edittree) { - nodeSetActiveID(snode->edittree, ID_MA, wmn->reference); + nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference); } } break; @@ -404,7 +402,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) else if (ED_node_is_geometry(snode)) { /* Rather strict check: only redraw when the reference matches the current editor's ID. */ if (wmn->data == ND_MODIFIER) { - if (wmn->reference == snode->id || snode->id == NULL) { + if (wmn->reference == snode->id || snode->id == nullptr) { ED_area_tag_refresh(area); } } @@ -447,7 +445,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) /* note that nodeUpdateID is already called by BKE_image_signal() on all * scenes so really this is just to know if the images is used in the compo else * painting on images could become very slow when the compositor is open. */ - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -457,7 +455,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -485,7 +483,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) static void node_area_refresh(const struct bContext *C, ScrArea *area) { /* default now: refresh node is starting preview */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; snode_set_context(C); @@ -494,19 +492,19 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) if (GS(snode->id->name) == ID_MA) { Material *ma = (Material *)snode->id; if (ma->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_LA) { Light *la = (Light *)snode->id; if (la->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_WO) { World *wo = (World *)snode->id; if (wo->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -516,7 +514,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) /* recalc is set on 3d view changes for auto compo */ if (snode->runtime->recalc) { snode->runtime->recalc = false; - node_render_changed_exec((struct bContext *)C, NULL); + node_render_changed_exec((struct bContext *)C, nullptr); } else { ED_node_composite_job(C, snode->nodetree, scene); @@ -526,7 +524,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) else if (snode->nodetree->type == NTREE_TEXTURE) { Tex *tex = (Tex *)snode->id; if (tex->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -535,14 +533,11 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) static SpaceLink *node_duplicate(SpaceLink *sl) { SpaceNode *snode = (SpaceNode *)sl; - SpaceNode *snoden = MEM_dupallocN(snode); + SpaceNode *snoden = (SpaceNode *)MEM_dupallocN(snode); BLI_duplicatelist(&snoden->treepath, &snode->treepath); - if (snode->runtime != NULL) { - snoden->runtime = MEM_dupallocN(snode->runtime); - BLI_listbase_clear(&snoden->runtime->linkdrag); - } + snoden->runtime = nullptr; /* NOTE: no need to set node tree user counts, * the editor only keeps at least 1 (id_us_ensure_real), @@ -596,7 +591,7 @@ void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(®ion->v2d, @@ -710,7 +705,7 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) } /* this region dropbox definition */ -static void node_dropboxes(void) +static void node_dropboxes() { ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW); @@ -719,37 +714,37 @@ static void node_dropboxes(void) node_object_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_collection", node_collection_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_texture", node_texture_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_group", node_group_drop_poll, node_group_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_file", node_ima_drop_poll, node_id_path_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_mask", node_mask_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); } /* ************* end drop *********** */ @@ -843,7 +838,7 @@ static void node_region_listener(const wmRegionListenerParams *params) } const char *node_context_dir[] = { - "selected_nodes", "active_node", "light", "material", "world", NULL}; + "selected_nodes", "active_node", "light", "material", "world", nullptr}; static int /*eContextResult*/ node_context(const bContext *C, const char *member, bContextDataResult *result) @@ -855,10 +850,8 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_OK; } if (CTX_data_equals(member, "selected_nodes")) { - bNode *node; - if (snode->edittree) { - for (node = snode->edittree->nodes.last; node; node = node->prev) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) { if (node->flag & NODE_SELECT) { CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node); } @@ -907,11 +900,11 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_MEMBER_NOT_FOUND; } -static void node_widgets(void) +static void node_widgets() { - /* create the widgetmap for the area here */ - wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure( - &(const struct wmGizmoMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW}); + /* Create the widget-map for the area here. */ + wmGizmoMapType_Params params{SPACE_NODE, RGN_TYPE_WINDOW}; + wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(¶ms); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_transform); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams); @@ -928,15 +921,15 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I */ BLI_freelistN(&snode->treepath); - /* XXX Untested in case new_id != NULL... */ + /* XXX Untested in case new_id != nullptr... */ snode->id = new_id; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; + snode->from = nullptr; + snode->nodetree = nullptr; + snode->edittree = nullptr; } else if (GS(old_id->name) == ID_OB) { if (snode->from == old_id) { - if (new_id == NULL) { + if (new_id == nullptr) { snode->flag &= ~SNODE_PIN; } snode->from = new_id; @@ -952,7 +945,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I else if (GS(old_id->name) == ID_NT) { bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path->next) { + for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) { if ((ID *)path->nodetree == old_id) { path->nodetree = (bNodeTree *)new_id; id_us_ensure_real(new_id); @@ -961,7 +954,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* first nodetree in path is same as snode->nodetree */ snode->nodetree = path->nodetree; } - if (path->nodetree == NULL) { + if (path->nodetree == nullptr) { break; } } @@ -977,24 +970,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* edittree is just the last in the path, * set this directly since the path may have been shortened above */ if (snode->treepath.last) { - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; } else { - snode->edittree = NULL; + snode->edittree = nullptr; } } } static int node_space_subtype_get(ScrArea *area) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; return rna_node_tree_idname_to_enum(snode->tree_idname); } static void node_space_subtype_set(ScrArea *area, int value) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value)); } @@ -1011,7 +1004,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node"); + SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node"); ARegionType *art; st->spaceid = SPACE_NODE; @@ -1034,7 +1027,7 @@ void ED_spacetype_node(void) st->space_subtype_set = node_space_subtype_set; /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; @@ -1048,7 +1041,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; @@ -1059,7 +1052,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -1070,7 +1063,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: toolbar */ - art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 738db28a2b6..e449e4a609b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -763,7 +763,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(tselem->id); + BKE_copybuffer_copy_tag_ID(tselem->id); num_ids++; } } @@ -781,7 +781,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); char str[FILE_MAX]; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree); if (num_ids == 0) { @@ -790,7 +790,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) } BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 4b6c5e29d77..f6f8e45590f 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -28,6 +28,7 @@ #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "MEM_guardedalloc.h" @@ -400,7 +401,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } - return 0; + return WM_drag_is_ID_type(drag, ID_IM); } static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -416,7 +417,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_MC); } static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -432,35 +434,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_SO); } static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) { - /* Copy drag path to properties. */ - if (RNA_struct_find_property(drop->ptr, "filepath")) { - RNA_string_set(drop->ptr, "filepath", drag->path); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); + /* ID dropped. */ + if (id != NULL) { + const ID_Type id_type = GS(id->name); + if (id_type == ID_IM) { + Image *ima = (Image *)id; + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; + BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file)); + RNA_string_set(drop->ptr, "directory", dir); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } + else if (id_type == ID_MC) { + MovieClip *clip = (MovieClip *)id; + RNA_string_set(drop->ptr, "filepath", clip->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } + else if (id_type == ID_SO) { + bSound *sound = (bSound *)id; + RNA_string_set(drop->ptr, "filepath", sound->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } } + /* Path dropped. */ + else if (drag->path[0]) { + if (RNA_struct_find_property(drop->ptr, "filepath")) { + RNA_string_set(drop->ptr, "filepath", drag->path); + } + if (RNA_struct_find_property(drop->ptr, "directory")) { + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; - if (RNA_struct_find_property(drop->ptr, "directory")) { - PointerRNA itemptr; - char dir[FILE_MAX], file[FILE_MAX]; - - BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); + BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); - RNA_string_set(drop->ptr, "directory", dir); + RNA_string_set(drop->ptr, "directory", dir); - RNA_collection_clear(drop->ptr, "files"); - RNA_collection_add(drop->ptr, "files", &itemptr); - RNA_string_set(&itemptr, "name", file); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } } } /* This region dropbox definition. */ -static void sequencer_dropboxes(void) -{ - ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); +static void sequencer_dropboxes_add_to_lb(ListBase *lb) +{ WM_dropbox_add( lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL); WM_dropbox_add( @@ -469,6 +497,14 @@ static void sequencer_dropboxes(void) lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL); } +static void sequencer_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + sequencer_dropboxes_add_to_lb(lb); + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + sequencer_dropboxes_add_to_lb(lb); +} + /* ************* end drop *********** */ /* DO NOT make this static, this hides the symbol and breaks API generation script. */ @@ -757,6 +793,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region) /* Own keymap. */ keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0); WM_event_add_keymap_handler_v2d_mask(®ion->handlers, keymap); + + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + WM_event_add_dropbox_handler(®ion->handlers, lb); } static void sequencer_preview_region_layout(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 91fe1bc01b7..27446fe1a94 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -41,10 +41,10 @@ set(SRC spreadsheet_data_source.cc spreadsheet_data_source_geometry.cc spreadsheet_dataset_draw.cc - spreadsheet_dataset_layout.cc spreadsheet_draw.cc spreadsheet_layout.cc spreadsheet_ops.cc + spreadsheet_panels.cc spreadsheet_row_filter.cc spreadsheet_row_filter_ui.cc @@ -56,7 +56,6 @@ set(SRC spreadsheet_data_source.hh spreadsheet_data_source_geometry.hh spreadsheet_dataset_draw.hh - spreadsheet_dataset_layout.hh spreadsheet_draw.hh spreadsheet_intern.hh spreadsheet_layout.hh @@ -67,4 +66,14 @@ set(SRC set(LIB ) +if(WITH_OPENVDB) + list(APPEND INC_SYS + ${OPENVDB_INCLUDE_DIRS} + ) + list(APPEND LIB + ${OPENVDB_LIBRARIES} + ) + add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) +endif() + blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index d54af7ffe2c..b37706e02e8 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -41,6 +41,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLT_translation.h" + #include "BLF_api.h" #include "spreadsheet_intern.hh" @@ -319,6 +321,8 @@ static float get_default_column_width(const ColumnValues &values) return 4.0f * float_width; case SPREADSHEET_VALUE_TYPE_INSTANCES: return 8.0f; + case SPREADSHEET_VALUE_TYPE_STRING: + return 5.0f; } return float_width; } @@ -589,35 +593,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa spreadsheet_header_region_listener(params); } -static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region) -{ - region->v2d.scroll |= V2D_SCROLL_RIGHT; - region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM); - region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; - - UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); - - wmKeyMap *keymap = WM_keymap_ensure( - wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0); - WM_event_add_keymap_handler(®ion->handlers, keymap); -} - static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region) { spreadsheet_update_context_path(C); - - View2D *v2d = ®ion->v2d; - UI_view2d_view_ortho(v2d); - UI_ThemeClearColor(TH_BACK); - - draw_dataset_in_region(C, region); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers */ - UI_view2d_scrollers_draw(v2d, nullptr); + ED_region_panels(C, region); } static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region) @@ -708,11 +687,12 @@ void ED_spacetype_spreadsheet(void) /* regions: channels */ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region"); art->regionid = RGN_TYPE_CHANNELS; - art->prefsizex = 200 + V2D_SCROLL_WIDTH; + art->prefsizex = 150 + V2D_SCROLL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; - art->init = spreadsheet_dataset_region_init; + art->init = ED_region_panels_init; art->draw = spreadsheet_dataset_region_draw; art->listener = spreadsheet_dataset_region_listener; + blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art); BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh index 97170693cb3..c11b4a2b23d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh @@ -58,6 +58,7 @@ class CellValue { std::optional<ObjectCellValue> value_object; std::optional<CollectionCellValue> value_collection; std::optional<GeometrySetCellValue> value_geometry_set; + std::optional<std::string> value_string; }; } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index c1d345d1861..8cdb462718d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -20,6 +20,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" +#include "BKE_volume.h" #include "DNA_ID.h" #include "DNA_mesh_types.h" @@ -33,6 +34,11 @@ #include "NOD_geometry_nodes_eval_log.hh" +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_enum_types.h" + #include "FN_field_cpp_type.hh" #include "bmesh.h" @@ -72,7 +78,7 @@ static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type( void ExtraColumns::foreach_default_column_ids( FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const { - for (const auto &item : columns_.items()) { + for (const auto item : columns_.items()) { SpreadsheetColumnID column_id; column_id.name = (char *)item.key.c_str(); fn(column_id, true); @@ -112,6 +118,9 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values( r_cell_value.value_color = *( const ColorGeometry4f *)value; break; + case SPREADSHEET_VALUE_TYPE_STRING: + r_cell_value.value_string = *(const std::string *)value; + break; case SPREADSHEET_VALUE_TYPE_INSTANCES: break; } @@ -159,12 +168,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( if (!attribute) { return {}; } - const fn::GVArray *varray = scope_.add(std::move(attribute.varray)); + fn::GVArray varray = std::move(attribute.varray); if (attribute.domain != domain_) { return {}; } - int domain_size = varray->size(); - const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type()); + int domain_size = varray.size(); + const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type()); switch (type) { case CD_PROP_FLOAT: return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT, @@ -172,7 +181,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float = value; }); case CD_PROP_INT32: @@ -182,7 +191,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { int value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_int = value; }, STREQ(column_id.name, "id") ? 5.5f : 0.0f); @@ -192,7 +201,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { bool value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_bool = value; }); case CD_PROP_FLOAT2: { @@ -201,7 +210,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float2 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float2 = value; }); } @@ -211,7 +220,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float3 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float3 = value; }); } @@ -221,7 +230,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { ColorGeometry4f value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_color = value; }); } @@ -487,9 +496,93 @@ int InstancesDataSource::tot_rows() const return component_->instances_amount(); } +void VolumeDataSource::foreach_default_column_ids( + FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const +{ + if (component_->is_empty()) { + return; + } + + for (const char *name : {"Grid Name", "Data Type", "Class"}) { + SpreadsheetColumnID column_id{(char *)name}; + fn(column_id, false); + } +} + +std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values( + const SpreadsheetColumnID &column_id) const +{ + const Volume *volume = component_->get_for_read(); + if (volume == nullptr) { + return {}; + } + +#ifdef WITH_OPENVDB + const int size = this->tot_rows(); + if (STREQ(column_id.name, "Grid Name")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Grid Name"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + r_cell_value.value_string = BKE_volume_grid_name(volume_grid); + }, + 6.0f); + } + if (STREQ(column_id.name, "Data Type")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Type"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + const VolumeGridType type = BKE_volume_grid_type(volume_grid); + const char *name = nullptr; + RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name); + r_cell_value.value_string = IFACE_(name); + }, + 5.0f); + } + if (STREQ(column_id.name, "Class")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Class"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); + openvdb::GridClass grid_class = grid->getGridClass(); + if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) { + r_cell_value.value_string = IFACE_("Fog Volume"); + } + else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { + r_cell_value.value_string = IFACE_("Level Set"); + } + else { + r_cell_value.value_string = IFACE_("Unkown"); + } + }, + 5.0f); + } +#else + UNUSED_VARS(column_id); +#endif + + return {}; +} + +int VolumeDataSource::tot_rows() const +{ + const Volume *volume = component_->get_for_read(); + if (volume == nullptr) { + return 0; + } + return BKE_volume_num_grids(volume); +} + GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type) + Object *object_eval) { GeometrySet geometry_set; if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { @@ -521,7 +614,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { + if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); if (mesh == nullptr) { return geometry_set; @@ -644,7 +737,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const int domain_size = component.attribute_domain_size(domain); - for (const auto &item : fields_to_show.items()) { + for (const auto item : fields_to_show.items()) { StringRef name = item.key; const GField &field = item.value; @@ -668,8 +761,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); - GeometrySet geometry_set = spreadsheet_get_display_geometry_set( - sspreadsheet, object_eval, component_type); + GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); if (!geometry_set.has(component_type)) { return {}; @@ -682,6 +774,9 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object if (component_type == GEO_COMPONENT_TYPE_INSTANCES) { return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns)); } + if (component_type == GEO_COMPONENT_TYPE_VOLUME) { + return std::make_unique<VolumeDataSource>(geometry_set); + } return std::make_unique<GeometryDataSource>( object_eval, geometry_set, component_type, domain, std::move(extra_columns)); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 6c88a94f585..a4114dd1f6a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -116,6 +116,26 @@ class InstancesDataSource : public DataSource { int tot_rows() const override; }; +class VolumeDataSource : public DataSource { + const GeometrySet geometry_set_; + const VolumeComponent *component_; + + public: + VolumeDataSource(GeometrySet geometry_set) + : geometry_set_(std::move(geometry_set)), + component_(geometry_set_.get_component_for_read<VolumeComponent>()) + { + } + + void foreach_default_column_ids( + FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override; + + std::unique_ptr<ColumnValues> get_column_values( + const SpreadsheetColumnID &column_id) const override; + + int tot_rows() const override; +}; + std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 4cf6d14cbda..2a81b56d129 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -14,275 +14,226 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include <array> - #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "BKE_context.h" - -#include "BLF_api.h" - -#include "BLI_rect.h" +#include "BKE_volume.h" #include "RNA_access.h" #include "UI_interface.h" -#include "UI_view2d.h" +#include "UI_interface.hh" +#include "UI_tree_view.hh" #include "WM_types.h" +#include "BLT_translation.h" + #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_draw.hh" #include "spreadsheet_intern.hh" -static int is_component_row_selected(struct uiBut *but, const void *arg) -{ - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg; +namespace blender::ed::spreadsheet { - GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but); - AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but); +class GeometryDataSetTreeView; - const bool is_component_selected = (GeometryComponentType) - sspreadsheet->geometry_component_type == component; - const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain; - bool is_selected = is_component_selected && is_domain_selected; +class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { + GeometryComponentType component_type_; + std::optional<AttributeDomain> domain_; + BIFIconID icon_; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { - is_selected = is_component_selected; - } + public: + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon); + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon); - return is_selected; -} + void on_activate() override; -namespace blender::ed::spreadsheet { + void build_row(uiLayout &row) override; -/* -------------------------------------------------------------------- */ -/* Draw Context */ + protected: + std::optional<bool> should_be_active() const override; + bool supports_collapsing() const override; -class DatasetDrawContext { - std::array<int, 2> mval_; + private: + GeometryDataSetTreeView &get_tree() const; + std::optional<int> count() const; +}; - public: - const SpaceSpreadsheet *sspreadsheet; - Object *object_eval; - /* Current geometry set, changes per component. */ - GeometrySet current_geometry_set; +class GeometryDataSetTreeView : public ui::AbstractTreeView { + GeometrySet geometry_set_; + const bContext &C_; + SpaceSpreadsheet &sspreadsheet_; + bScreen &screen_; - DatasetDrawContext(const bContext *C); + friend class GeometryDataSetTreeViewItem; - GeometrySet geometry_set_from_component(GeometryComponentType component); - const std::array<int, 2> &cursor_mval() const; -}; - -DatasetDrawContext::DatasetDrawContext(const bContext *C) - : sspreadsheet(CTX_wm_space_spreadsheet(C)), - object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C))) -{ - const wmWindow *win = CTX_wm_window(C); - const ARegion *region = CTX_wm_region(C); - mval_ = {win->eventstate->xy[0] - region->winrct.xmin, - win->eventstate->xy[1] - region->winrct.ymin}; -} + public: + GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C) + : geometry_set_(std::move(geometry_set)), + C_(C), + sspreadsheet_(*CTX_wm_space_spreadsheet(&C)), + screen_(*CTX_wm_screen(&C)) + { + } -GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component) -{ - return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component); -} + void build_tree() override + { + GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER); + + GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA); + curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE, + ATTR_DOMAIN_POINT, + IFACE_("Control Point"), + ICON_CURVE_BEZCIRCLE); + curve.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH); + + GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA); + pointcloud.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS); + } +}; -const std::array<int, 2> &DatasetDrawContext::cursor_mval() const +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(std::nullopt), icon_(icon) { - return mval_; + label_ = label; + this->set_collapsed(false); } - -/* -------------------------------------------------------------------- */ -/* Drawer */ - -DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region, - uiBlock &block, - DatasetDrawContext &draw_context) - : row_height(UI_UNIT_Y), - xmin(region->v2d.cur.xmin), - xmax(region->v2d.cur.xmax), - block(block), - v2d(region->v2d), - draw_context(draw_context) +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(domain), icon_(icon) { + label_ = label; } -void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout) +void GeometryDataSetTreeViewItem::on_activate() { - for (const DatasetComponentLayoutInfo &component : layout.components) { - draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type); - - draw_component_row(component); - - /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size - * array so uses optionals to support skipping enum values that shouldn't be displayed for a - * component). */ - for (const auto &optional_domain : component.attr_domains) { - if (!optional_domain) { - continue; - } - - const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain; - draw_attribute_domain_row(component, domain_info); - } + GeometryDataSetTreeView &tree_view = this->get_tree(); + bContext &C = const_cast<bContext &>(tree_view.C_); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; + tree_view.sspreadsheet_.geometry_component_type = component_type_; + if (domain_) { + tree_view.sspreadsheet_.attribute_domain = *domain_; } + PointerRNA ptr; + RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); } -static int element_count_from_instances(const GeometrySet &geometry_set) +void GeometryDataSetTreeViewItem::build_row(uiLayout &row) { - if (geometry_set.has_instances()) { - const InstancesComponent *instances_component = - geometry_set.get_component_for_read<InstancesComponent>(); - return instances_component->instances_amount(); + uiItemL(&row, label_.c_str(), icon_); + + if (const std::optional<int> count = this->count()) { + /* Using the tree row button instead of a separate right aligned button gives padding + * to the right side of the number, which it didn't have with the button. */ + char element_count[7]; + BLI_str_format_attribute_domain_size(element_count, *count); + UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count); } - return 0; } -static int element_count_from_component_domain(const GeometrySet &geometry_set, - GeometryComponentType component, - AttributeDomain domain) +std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const { - if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) { - const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>(); - return mesh_component->attribute_domain_size(domain); - } + GeometryDataSetTreeView &tree_view = this->get_tree(); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) { - const PointCloudComponent *point_cloud_component = - geometry_set.get_component_for_read<PointCloudComponent>(); - return point_cloud_component->attribute_domain_size(domain); + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + return sspreadsheet.geometry_component_type == component_type_; } - if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) { - const VolumeComponent *volume_component = - geometry_set.get_component_for_read<VolumeComponent>(); - return volume_component->attribute_domain_size(domain); + if (!domain_) { + return false; } - if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - return curve_component->attribute_domain_size(domain); - } - - return 0; + return sspreadsheet.geometry_component_type == component_type_ && + sspreadsheet.attribute_domain == *domain_; } -void DatasetRegionDrawer::draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - BIFIconID icon, - const char *label, - const bool is_active) +bool GeometryDataSetTreeViewItem::supports_collapsing() const { + return false; +} - const float row_height = UI_UNIT_Y; - const float padding_x = UI_UNIT_X * 0.25f; - - const rctf rect = {float(xmin) + padding_x, - float(xmax) - V2D_SCROLL_HANDLE_WIDTH, - ymin_offset - row_height, - ymin_offset}; - - char element_count[7]; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { - BLI_str_format_attribute_domain_size( - element_count, element_count_from_instances(draw_context.current_geometry_set)); - } - else { - BLI_str_format_attribute_domain_size( - element_count, - domain ? element_count_from_component_domain( - draw_context.current_geometry_set, component, *domain) : - 0); - } +GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const +{ + return static_cast<GeometryDataSetTreeView &>(this->get_tree_view()); +} - std::string label_and_element_count = label; - label_and_element_count += UI_SEP_CHAR; - label_and_element_count += element_count; - - uiBut *bt = uiDefIconTextButO(&block, - UI_BTYPE_DATASETROW, - "SPREADSHEET_OT_change_spreadsheet_data_source", - 0, - icon, - label, - rect.xmin, - rect.ymin, - BLI_rctf_size_x(&rect), - BLI_rctf_size_y(&rect), - nullptr); - - UI_but_datasetrow_indentation_set(bt, indentation); - - if (is_active) { - UI_but_hint_drawstr_set(bt, element_count); - UI_but_datasetrow_component_set(bt, component); - if (domain) { - UI_but_datasetrow_domain_set(bt, *domain); - } - UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet); +std::optional<int> GeometryDataSetTreeViewItem::count() const +{ + GeometryDataSetTreeView &tree_view = this->get_tree(); + GeometrySet &geometry = tree_view.geometry_set_; - PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt); - RNA_int_set(but_ptr, "component_type", component); - if (domain) { - RNA_int_set(but_ptr, "attribute_domain_type", *domain); + /* Special case for volumes since there is no grid domain. */ + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + if (const Volume *volume = geometry.get_volume_for_read()) { + return BKE_volume_num_grids(volume); } + return 0; } - ymin_offset -= row_height; -} - -void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info) -{ - if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true); + if (!domain_) { + return std::nullopt; } - else { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false); + + if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) { + return component->attribute_domain_size(*domain_); } -} -void DatasetRegionDrawer::draw_attribute_domain_row( - const DatasetComponentLayoutInfo &component_info, - const DatasetAttrDomainLayoutInfo &domain_info) -{ - draw_dataset_row( - 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true); + return 0; } -/* -------------------------------------------------------------------- */ -/* Drawer */ - -void draw_dataset_in_region(const bContext *C, ARegion *region) +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel) { - DatasetDrawContext draw_context{C}; - if (!draw_context.object_eval) { - /* No object means nothing to display. Keep the region empty. */ + const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)); + if (!object) { return; } + uiLayout *layout = panel->layout; - uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); - - DatasetRegionDrawer drawer{region, *block, draw_context}; + uiBlock *block = uiLayoutGetBlock(layout); - /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for - * that. */ - drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height; + UI_block_layout_set_current(block, layout); - const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy(); - drawer.draw_hierarchy(hierarchy); -#ifndef NDEBUG - dataset_layout_hierarchy_sanity_check(hierarchy); -#endif + ui::AbstractTreeView *tree_view = UI_block_add_view( + *block, + "Data Set Tree View", + std::make_unique<GeometryDataSetTreeView>( + spreadsheet_get_display_geometry_set(sspreadsheet, object), *C)); - UI_block_end(C, block); - UI_view2d_totRect_set(®ion->v2d, region->winx, abs(drawer.ymin_offset)); - UI_block_draw(C, block); + ui::TreeViewBuilder builder(*block); + builder.build_tree_view(*tree_view); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh index 19906d73e7f..4a604533f11 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh @@ -16,49 +16,11 @@ #pragma once -#include <array> - -#include "BKE_geometry_set.hh" -#include "UI_interface.h" -#include "spreadsheet_dataset_layout.hh" - -struct ARegion; -struct View2D; +struct Panel; struct bContext; -struct uiBlock; namespace blender::ed::spreadsheet { -class DatasetDrawContext; - -class DatasetRegionDrawer { - public: - const int row_height; - float ymin_offset = 0; - - int xmin; - int xmax; - uiBlock █ - const View2D &v2d; - DatasetDrawContext &draw_context; - - DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context); - - void draw_hierarchy(const DatasetLayoutHierarchy &layout); - - void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component, - const DatasetAttrDomainLayoutInfo &domain_info); - void draw_component_row(const DatasetComponentLayoutInfo &component_info); - - private: - void draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - const BIFIconID icon, - const char *label, - const bool is_active); -}; - -void draw_dataset_in_region(const bContext *C, ARegion *region); +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc deleted file mode 100644 index abbad8c7088..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <optional> - -#include "BLI_span.hh" - -#include "BLT_translation.h" - -#include "spreadsheet_dataset_layout.hh" - -namespace blender::ed::spreadsheet { - -#define ATTR_INFO(type, label, icon) \ - std::optional<DatasetAttrDomainLayoutInfo> \ - { \ - std::in_place, type, label, icon \ - } -#define ATTR_INFO_NONE(type) \ - { \ - std::nullopt \ - } - -/** - * Definition for the component->attribute-domain hierarchy. - * Constructed at compile time. - * - * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain - * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use - * array designators for this (which C++ doesn't support). - */ -constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = { - { - GEO_COMPONENT_TYPE_MESH, - N_("Mesh"), - ICON_MESH_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL), - ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL), - ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL), - ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER), - }, - }, - { - GEO_COMPONENT_TYPE_CURVE, - N_("Curves"), - ICON_CURVE_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE), - ATTR_INFO_NONE(ATTR_DOMAIN_EDGE), - ATTR_INFO_NONE(ATTR_DOMAIN_CORNER), - ATTR_INFO_NONE(ATTR_DOMAIN_FACE), - ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH), - }, - }, - { - GEO_COMPONENT_TYPE_POINT_CLOUD, - N_("Point Cloud"), - ICON_POINTCLOUD_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT), - }, - }, - { - GEO_COMPONENT_TYPE_INSTANCES, - N_("Instances"), - ICON_EMPTY_AXIS, - {}, - }, -}; - -#undef ATTR_INFO -#undef ATTR_INFO_LABEL - -DatasetLayoutHierarchy dataset_layout_hierarchy() -{ - return DatasetLayoutHierarchy{ - Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}}; -} - -#ifndef NDEBUG -/** - * Debug-only sanity check for correct attribute domain initialization (order/indices must - * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most - * likely mistakes. - */ -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy) -{ - for (const DatasetComponentLayoutInfo &component : hierarchy.components) { - for (uint i = 0; i < component.attr_domains.size(); i++) { - if (component.attr_domains[i]) { - BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i)); - } - } - } -} -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh deleted file mode 100644 index d463739a0fa..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include <array> -#include <optional> - -/* Enum definitions... */ -#include "BKE_attribute.h" -#include "BKE_geometry_set.h" - -#include "BLI_span.hh" - -/* More enum definitions... */ -#include "UI_resources.h" - -#pragma once - -namespace blender::ed::spreadsheet { - -struct DatasetAttrDomainLayoutInfo { - AttributeDomain type; - const char *label; - BIFIconID icon; - - constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon) - : type(type), label(label), icon(icon) - { - } -}; - -struct DatasetComponentLayoutInfo { - GeometryComponentType type; - const char *label; - BIFIconID icon; - /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all - * values need displaying for all parent components. Hence the optional use. */ - using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>; - const AttrDomainArray attr_domains; -}; - -struct DatasetLayoutHierarchy { - /** The components for display (with layout info like icon and label). Each component stores - * the attribute domains it wants to display (also with layout info like icon and label). */ - const Span<DatasetComponentLayoutInfo> components; -}; - -DatasetLayoutHierarchy dataset_layout_hierarchy(); - -#ifndef NDEBUG -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy); -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh index 8b050c2e69b..e62835d5792 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime { }; struct bContext; +struct ARegionType; void spreadsheet_operatortypes(void); void spreadsheet_update_context_path(const bContext *C); @@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, namespace blender::ed::spreadsheet { GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type); -} + Object *object_eval); + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type); + +} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 355899be279..202523c0e64 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -228,6 +228,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { 0, nullptr); } + else if (cell_value.value_string.has_value()) { + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_NONE, + cell_value.value_string->c_str(), + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + } } void draw_float_vector(const CellDrawParams ¶ms, const Span<float> values) const diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc new file mode 100644 index 00000000000..8f923ea4a63 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "spreadsheet_dataset_draw.hh" +#include "spreadsheet_intern.hh" + +namespace blender::ed::spreadsheet { + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type) +{ + PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); + strcpy(panel_type->label, N_("Data Set")); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + panel_type->flag = PANEL_TYPE_NO_HEADER; + panel_type->draw = spreadsheet_data_set_panel_draw; + BLI_addtail(®ion_type.paneltypes, panel_type); +} + +} // namespace blender::ed::spreadsheet
\ No newline at end of file diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index d56049990b4..a07abac4474 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -105,12 +105,15 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, return row_filter.value_string; } return ""; - case SPREADSHEET_VALUE_TYPE_COLOR: + case SPREADSHEET_VALUE_TYPE_COLOR: { std::ostringstream result; result.precision(3); result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1] << ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")"; return result.str(); + } + case SPREADSHEET_VALUE_TYPE_STRING: + return row_filter.value_string; } BLI_assert_unreachable(); return ""; @@ -234,6 +237,8 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE); uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); break; + case SPREADSHEET_VALUE_TYPE_STRING: + break; } } diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index b541b65d676..f8d16e396d4 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -70,7 +70,7 @@ static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc) static void text_font_begin(const TextDrawContext *tdc) { - BLF_size(tdc->font_id, tdc->lheight_px, 72); + BLF_size(tdc->font_id, (float)tdc->lheight_px, 72); } static void text_font_end(const TextDrawContext *UNUSED(tdc)) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 458a1be0308..3c0ffa29bbd 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -86,6 +86,30 @@ static void test_line_start(char c, bool *r_last_state) } /** + * This function receives a character and returns its closing pair if it exists. + * \param character: Character to find the closing pair. + * \return The closing pair of the character if it exists. + */ +static char text_closing_character_pair_get(const char character) +{ + + switch (character) { + case '(': + return ')'; + case '[': + return ']'; + case '{': + return '}'; + case '"': + return '"'; + case '\'': + return '\''; + default: + return 0; + } +} + +/** * This function converts the indentation tabs from a buffer to spaces. * \param in_buf: A pointer to a cstring. * \param tab_size: The size, in spaces, of the tab character. @@ -2403,7 +2427,17 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } } - + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + const char *curr = text->curl->line + text->curc; + if (*curr != '\0') { + const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line); + if ((curr != prev) && /* When back-spacing from the start of the line. */ + (*curr == text_closing_character_pair_get(*prev))) { + txt_move_right(text, false); + txt_backspace_char(text); + } + } + } txt_backspace_char(text); } else if (type == DEL_NEXT_WORD) { @@ -3443,6 +3477,12 @@ static int text_insert_exec(bContext *C, wmOperator *op) while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, str_len, &i); done |= txt_add_char(text, code); + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + if (text_closing_character_pair_get(code)) { + done |= txt_add_char(text, text_closing_character_pair_get(code)); + txt_move_left(text, false); + } + } } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6b9da431510..48f39f835c5 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -48,58 +48,6 @@ #include "view3d_intern.h" /* bad level include */ -/* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */ -/* 32 values of sin function (still same result!) */ -#define CIRCLE_RESOL 32 - -static const float sinval[CIRCLE_RESOL] = { - 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, - 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, - 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, - -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, - -0.57126821, -0.39435585, -0.20129852, 0.00000000, -}; - -/* 32 values of cos function (still same result!) */ -static const float cosval[CIRCLE_RESOL] = { - 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, - 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, - -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, - -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, - 0.82076344, 0.91895781, 0.97952994, 1.00000000, -}; - -static void circball_array_fill(const float verts[CIRCLE_RESOL][3], - const float cent[3], - float rad, - const float tmat[4][4]) -{ - float vx[3], vy[3]; - float *viter = (float *)verts; - - mul_v3_v3fl(vx, tmat[0], rad); - mul_v3_v3fl(vy, tmat[1], rad); - - for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { - viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; - viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; - viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; - } -} - -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) -{ - float verts[CIRCLE_RESOL][3]; - - circball_array_fill(verts, cent, rad, tmat); - - immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); - for (int i = 0; i < CIRCLE_RESOL; i++) { - immVertex3fv(pos, verts[i]); - } - immEnd(); -} - #ifdef VIEW3D_CAMERA_BORDER_HACK uchar view3d_camera_border_hack_col[3]; bool view3d_camera_border_hack_test = false; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index bf16dfb469c..e54ef3c931a 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -853,7 +853,6 @@ static void view3d_dropboxes(void) drop->draw = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; - drop->opcontext = WM_OP_EXEC_DEFAULT; /* Not really needed. */ drop = WM_dropbox_add(lb, "OBJECT_OT_transform_to_mouse", @@ -865,7 +864,6 @@ static void view3d_dropboxes(void) drop->draw = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; - drop->opcontext = WM_OP_INVOKE_DEFAULT; WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 1213614704d..ac80a70011a 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -95,9 +95,7 @@ typedef struct SnapCursorDataIntern { static SnapCursorDataIntern g_data_intern = { .state_default = {.prevpoint = NULL, - .snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | - SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_EDGE_PERPENDICULAR | - SCE_SNAP_MODE_EDGE_MIDPOINT), + .snap_elem_force = SCE_SNAP_MODE_GEOM, .plane_axis = 2, .color_point = {255, 255, 255, 255}, .color_line = {255, 255, 255, 128}, diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index fceb6553cab..6f6fa8b7576 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1318,10 +1318,9 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y } /** - * Draw info beside axes in bottom left-corner: + * Draw info beside axes in top-left corner: * frame-number, collection, object name, bone name (if available), marker name (if available). */ - static void draw_selected_name( Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset) { @@ -1344,14 +1343,13 @@ static void draw_selected_name( (ob == NULL) ? "" : " |"); } - /* - * info can contain: - * - a frame (7 + 2) - * - a collection name (MAX_NAME + 3) - * - 3 object names (MAX_NAME) - * - 2 BREAD_CRUMB_SEPARATORs (6) - * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! - * - a marker name (MAX_NAME + 3) + /* Info can contain: + * - A frame `(7 + 2)`. + * - A collection name `(MAX_NAME + 3)`. + * - 3 object names `(MAX_NAME)`. + * - 2 BREAD_CRUMB_SEPARATOR(s) `(6)`. + * - A SHAPE_KEY_PINNED marker and a trailing '\0' `(9+1)` - translated, so give some room! + * - A marker name `(MAX_NAME + 3)`. */ /* get name of marker on current frame (if available) */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 34e3b808b50..1082483dcd7 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -115,8 +115,10 @@ enum { CONSTRAIN_AXIS_Z = 2, }; -/* Constraining modes. - Off / Scene orientation / Global (or Local if Scene orientation is Global) */ +/** + * Constraining modes. + * Off / Scene orientation / Global (or Local if Scene orientation is Global). + */ enum { CONSTRAIN_MODE_OFF = 0, CONSTRAIN_MODE_1 = 1, @@ -163,7 +165,7 @@ typedef struct RulerInfo { typedef struct RulerItem { wmGizmo gz; - /* worldspace coords, middle being optional */ + /** World-space coords, middle being optional. */ float co[3][3]; int flag; @@ -643,7 +645,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_line_width(1.0f); BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 14.0f * U.pixelsize, U.dpi); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index eb8c043319c..823aa3b6643 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -63,19 +63,19 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) char str[FILE_MAX]; int num_copied = 0; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); /* context, selection, could be generalized */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - BKE_copybuffer_tag_ID(&ob->id); + BKE_copybuffer_copy_tag_ID(&ob->id); num_copied++; } } CTX_DATA_END; BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index cecd1765a17..8c1cab6bf14 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -45,10 +45,6 @@ #include "view3d_intern.h" -#define SNAP_MODE_GEOM \ - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) - static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; /** @@ -1308,7 +1304,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr), } /* Make sure you keep a consistent #snap_mode. */ - snap_state->snap_elem_force = SNAP_MODE_GEOM; + snap_state->snap_elem_force = SCE_SNAP_MODE_GEOM; return PLACE_SNAP_TO_GEOMETRY; } @@ -1319,7 +1315,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr), short snap_mode = 0; /* #toolsettings->snap_mode. */ const enum ePlace_SnapTo snap_to = value; if (snap_to == PLACE_SNAP_TO_GEOMETRY) { - snap_mode = SNAP_MODE_GEOM; + snap_mode = SCE_SNAP_MODE_GEOM; } V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get(); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index e09453b9957..d6a1cd930fc 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1094,17 +1094,10 @@ bool ED_view3d_autodist_simple(ARegion *region, return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc); } -bool ED_view3d_autodist_depth(ARegion *region, const int mval[2], int margin, float *depth) -{ - *depth = view_autodist_depth_margin(region, mval, margin); - - return (*depth != FLT_MAX); -} - static bool depth_segment_cb(int x, int y, void *userData) { struct { - ARegion *region; + const ViewDepths *vd; int margin; float depth; } *data = userData; @@ -1114,27 +1107,25 @@ static bool depth_segment_cb(int x, int y, void *userData) mval[0] = x; mval[1] = y; - depth = view_autodist_depth_margin(data->region, mval, data->margin); - - if (depth != FLT_MAX) { + if (ED_view3d_depth_read_cached(data->vd, mval, data->margin, &depth)) { data->depth = depth; return false; } return true; } -bool ED_view3d_autodist_depth_seg( - ARegion *region, const int mval_sta[2], const int mval_end[2], int margin, float *depth) +bool ED_view3d_depth_read_cached_seg( + const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth) { struct { - ARegion *region; + const ViewDepths *vd; int margin; float depth; } data = {NULL}; int p1[2]; int p2[2]; - data.region = region; + data.vd = vd; data.margin = margin; data.depth = FLT_MAX; @@ -1691,6 +1682,9 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd, return true; } + /* Grease-pencil and annotations also need the returned depth value to be high + * so the caller can detect it's invalid. */ + *r_depth = FLT_MAX; return false; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 46a664f10fa..6f0ce6c9326 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1731,9 +1731,9 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S View3DShading *xr_shading = &wm->xr.session_settings.shading; /* Flags that shouldn't be overridden by the 3D View shading. */ int flag_copy = 0; - if (v3d->shading.type != - OB_SOLID) { /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results - in distorted lighting when the view matrix has a scale factor. */ + if (v3d->shading.type != OB_SOLID) { + /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results in distorted + * lighting when the view matrix has a scale factor. */ flag_copy |= V3D_SHADING_WORLD_ORIENTATION; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e13e7c3f93a..d78cd13f8b8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -317,9 +317,9 @@ typedef struct TransSnap { /* Snapped Element Type (currently for objects only). */ char snapElem; /** snapping from this point (in global-space). */ - float snapPoint[3]; - /** to this point (in global-space). */ float snapTarget[3]; + /** to this point (in global-space). */ + float snapPoint[3]; float snapTargetGrid[3]; float snapNormal[3]; char snapNodeBorder; diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index a6658ae00a3..24d84bc2de8 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -159,8 +159,11 @@ static void TimeToTransData( copy_v2_v2(td2d->ih2, td2d->h2); /* Setup #TransData. */ - td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is - not float[3]. */ + + /* Usually #td2d->loc is used here. + * But this is for when the original location is not float[3]. */ + td->loc = time; + copy_v3_v3(td->iloc, td->loc); td->val = time; td->ival = *(time); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 87cc7a27829..c911331404f 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -144,7 +144,6 @@ static void *t_view_get(TransInfo *t) View3D *v3d = t->area->spacedata.first; return (void *)v3d; } - if (t->region) { return (void *)&t->region->v2d; } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 82574cffb82..233e32c0e48 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -403,7 +403,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) * since re-applying translation without rotation removes rotation. */ } else { - /* When transforming data that it's self stores rotation (objects, bones etc), + /* When transforming data that itself stores rotation (objects, bones etc), * apply rotation if it was applied (with the snap normal) previously. * This is needed because failing to rotate will leave the rotation at the last * value used before snapping was disabled. */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 7f27d5fb180..71f26ef0594 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -200,7 +200,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { bool draw_target = (t->tsnap.status & TARGET_INIT) && - (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); + (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); if (draw_target || validSnap(t)) { const float *loc_cur = NULL; @@ -483,7 +483,7 @@ void applySnapping(TransInfo *t, float *vec) } if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { - /* The snap has already been resolved for each transdata. */ + /* A similar snap will be applied to each transdata in `applyProject`. */ return; } @@ -574,70 +574,61 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) return true; } -static void initSnappingMode(TransInfo *t) +static short snap_mode_from_scene(TransInfo *t) { ToolSettings *ts = t->settings; - /* All obedit types will match. */ - const int obedit_type = t->obedit_type; - ViewLayer *view_layer = t->view_layer; - Base *base_act = view_layer->basact; + short r_snap_mode = SCE_SNAP_MODE_INCREMENT; if (t->spacetype == SPACE_NODE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_node_mode; + r_snap_mode = ts->snap_node_mode; } else if (t->spacetype == SPACE_IMAGE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_uv_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && + r_snap_mode = ts->snap_uv_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && (t->mode == TFM_TRANSLATION)) { - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; } } else if (t->spacetype == SPACE_SEQ) { - t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene); + r_snap_mode = SEQ_tool_settings_snap_mode_get(t->scene); } else if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* force project off when not supported */ - if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) { - t->tsnap.project = 0; - } - - t->tsnap.mode = ts->snap_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && - (t->mode == TFM_TRANSLATION)) { - /* Special case in which snap to increments is transformed to snap to grid. */ - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + /* All obedit types will match. */ + const int obedit_type = t->obedit_type; + if ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) || + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL, -1)) { + r_snap_mode = ts->snap_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && + (t->mode == TFM_TRANSLATION)) { + /* Special case in which snap to increments is transformed to snap to grid. */ + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; + } } } else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { /* No incremental snapping. */ - t->tsnap.mode = 0; - } - else { - /* Fallback. */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_mode = 0; } - if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* Only 3D view or UV. */ - /* Not with camera selected in camera view. */ + return r_snap_mode; +} - setSnappingCallback(t); +static short snap_select_type_get(TransInfo *t) +{ + short r_snap_select = SNAP_ALL; + ViewLayer *view_layer = t->view_layer; + Base *base_act = view_layer->basact; + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { + const int obedit_type = t->obedit_type; if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) * TODO: perform self snap in gpencil_strokes. * * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ - t->tsnap.modeSelect = SNAP_ALL; } else if ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { @@ -646,29 +637,44 @@ static void initSnappingMode(TransInfo *t) if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { /* Exclude editmesh if using proportional edit */ - t->tsnap.modeSelect = SNAP_NOT_ACTIVE; + r_snap_select = SNAP_NOT_ACTIVE; } - else { - t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE; + else if (!t->tsnap.snap_self) { + r_snap_select = SNAP_NOT_ACTIVE; } } else if ((obedit_type == -1) && base_act && base_act->object && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { /* Particles edit mode. */ - t->tsnap.modeSelect = SNAP_ALL; } else if (obedit_type == -1) { /* Object mode */ - t->tsnap.modeSelect = SNAP_NOT_SELECTED; - } - else { - /* Increment if snap is not possible */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_select = SNAP_NOT_SELECTED; } } else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - setSnappingCallback(t); - t->tsnap.modeSelect = SNAP_NOT_SELECTED; + r_snap_select = SNAP_NOT_SELECTED; + } + + return r_snap_select; +} + +static void initSnappingMode(TransInfo *t) +{ + ToolSettings *ts = t->settings; + t->tsnap.mode = snap_mode_from_scene(t); + t->tsnap.modeSelect = snap_select_type_get(t); + + if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { + /* Force project off when not supported. */ + t->tsnap.project = 0; + } + + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { + /* Not with camera selected in camera view. */ + if (!(t->options & CTX_CAMERA)) { + setSnappingCallback(t); + } } if (t->spacetype == SPACE_VIEW3D) { @@ -918,8 +924,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) mval[0] = t->mval[0]; mval[1] = t->mval[1]; - if (t->tsnap.mode & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { zero_v3(no); /* objects won't set this */ snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); found = snap_elem != 0; @@ -1249,7 +1254,7 @@ short snapObjectsTransform( t->depsgraph, t->region, t->view, - t->settings->snap_mode, + t->tsnap.mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 4a2ac806b2c..4b981e763f1 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -581,15 +581,15 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH struct RayCastAll_Data *data = userdata; data->raycast_callback(data->bvhdata, index, ray, hit); if (hit->index != -1) { - /* get all values in worldspace */ + /* Get all values in world-space. */ float location[3], normal[3]; float depth; - /* worldspace location */ + /* World-space location. */ mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); depth = (hit->dist + data->len_diff) / data->local_scale; - /* worldspace normal */ + /* World-space normal. */ copy_v3_v3(normal, hit->no); mul_m3_v3((float(*)[3])data->timat, normal); normalize_v3(normal); @@ -783,7 +783,7 @@ static bool raycastMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { @@ -953,7 +953,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index 9bf00ed7092..de7fcb7a728 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -190,7 +190,7 @@ void FEdgeXDetector::computeCurvatures(WXVertex *vertex) } // CURVATURE LAYER - // store all the curvature datas for each vertex + // store all the curvature data for each vertex // soc unused - real K1, K2 real cos2theta, sin2theta; diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 5e0302130af..28bb120bb17 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -178,11 +178,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> { } }; +namespace detail { +/* Utility class to make #is_field_v work. */ +struct TypedFieldBase { +}; +} // namespace detail + /** * A typed version of #GField. It has the same memory layout as #GField. */ -template<typename T> class Field : public GField { +template<typename T> class Field : public GField, detail::TypedFieldBase { public: + using base_type = T; + Field() = default; Field(GField field) : GField(std::move(field)) @@ -196,6 +204,11 @@ template<typename T> class Field : public GField { } }; +/** True when T is any Field<...> type. */ +template<typename T> +static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> && + !std::is_same_v<detail::TypedFieldBase, T>; + /** * A #FieldNode that allows composing existing fields into new fields. */ @@ -248,9 +261,9 @@ class FieldInput : public FieldNode { * Get the value of this specific input based on the given context. The returned virtual array, * should live at least as long as the passed in #scope. May return null. */ - virtual const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const = 0; + virtual GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const = 0; virtual std::string socket_inspection_name() const; blender::StringRef debug_name() const; @@ -268,9 +281,9 @@ class FieldContext { public: ~FieldContext() = default; - virtual const GVArray *get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const; + virtual GVArray get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const; }; /** @@ -289,8 +302,8 @@ class FieldEvaluator : NonMovable, NonCopyable { const FieldContext &context_; const IndexMask mask_; Vector<GField> fields_to_evaluate_; - Vector<GVMutableArray *> dst_varrays_; - Vector<const GVArray *> evaluated_varrays_; + Vector<GVMutableArray> dst_varrays_; + Vector<GVArray> evaluated_varrays_; Vector<OutputPointerInfo> output_pointer_infos_; bool is_evaluated_ = false; @@ -317,13 +330,12 @@ class FieldEvaluator : NonMovable, NonCopyable { * \param field: Field to add to the evaluator. * \param dst: Mutable virtual array that the evaluated result for this field is be written into. */ - int add_with_destination(GField field, GVMutableArray &dst); + int add_with_destination(GField field, GVMutableArray dst); /** Same as #add_with_destination but typed. */ - template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst) + template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(dst); - return this->add_with_destination(GField(std::move(field)), varray); + return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst))); } /** @@ -342,11 +354,10 @@ class FieldEvaluator : NonMovable, NonCopyable { */ template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst)); } - int add(GField field, const GVArray **varray_ptr); + int add(GField field, GVArray *varray_ptr); /** * \param field: Field to add to the evaluator. @@ -354,14 +365,14 @@ class FieldEvaluator : NonMovable, NonCopyable { * assigned to the given position. * \return Index of the field in the evaluator which can be used in the #get_evaluated methods. */ - template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr) + template<typename T> int add(Field<T> field, VArray<T> *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(nullptr); - output_pointer_infos_.append( - OutputPointerInfo{varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) { - *(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(varray); - }}); + dst_varrays_.append({}); + output_pointer_infos_.append(OutputPointerInfo{ + varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { + *(VArray<T> *)dst = varray.typed<T>(); + }}); return field_index; } @@ -378,14 +389,12 @@ class FieldEvaluator : NonMovable, NonCopyable { const GVArray &get_evaluated(const int field_index) const { BLI_assert(is_evaluated_); - return *evaluated_varrays_[field_index]; + return evaluated_varrays_[field_index]; } - template<typename T> const VArray<T> &get_evaluated(const int field_index) + template<typename T> VArray<T> get_evaluated(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(varray); - return *typed_varray; + return this->get_evaluated(field_index).typed<T>(); } /** @@ -396,11 +405,11 @@ class FieldEvaluator : NonMovable, NonCopyable { IndexMask get_evaluated_as_mask(const int field_index); }; -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays = {}); +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays = {}); /* -------------------------------------------------------------------- */ /** \name Utility functions for simple field creation and evaluation @@ -423,17 +432,19 @@ template<typename T> Field<T> make_constant_field(T value) return Field<T>{GField{std::move(operation), 0}}; } +GField make_constant_field(const CPPType &type, const void *value); + GField make_field_constant_if_possible(GField field); class IndexFieldInput final : public FieldInput { public: IndexFieldInput(); - static GVArray *get_index_varray(IndexMask mask, ResourceScope &scope); + static GVArray get_index_varray(IndexMask mask, ResourceScope &scope); - const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final; + GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final; uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; @@ -442,6 +453,52 @@ class IndexFieldInput final : public FieldInput { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Value or Field Class + * + * Utility class that wraps a single value and a field, to simplify accessing both of the types. + * \{ */ + +template<typename T> struct ValueOrField { + /** Value that is used when the field is empty. */ + T value{}; + Field<T> field; + + ValueOrField() = default; + + ValueOrField(T value) : value(std::move(value)) + { + } + + ValueOrField(Field<T> field) : field(std::move(field)) + { + } + + bool is_field() const + { + return (bool)this->field; + } + + Field<T> as_field() const + { + if (this->field) { + return this->field; + } + return make_constant_field(this->value); + } + + T as_value() const + { + if (this->field) { + /* This returns a default value when the field is not constant. */ + return evaluate_constant_field(this->field); + } + return this->value; + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name #FieldNode Inline Methods * \{ */ diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index 5e6f1b5a585..940faba6d70 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam { class FieldCPPType : public CPPType { private: - const CPPType &field_type_; + const CPPType &base_type_; public: template<typename T> FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name) : CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name), - field_type_(CPPType::get<T>()) + base_type_(CPPType::get<T>()) { } - const CPPType &field_type() const + const CPPType &base_type() const { - return field_type_; + return base_type_; } /* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */ @@ -60,6 +60,84 @@ class FieldCPPType : public CPPType { } }; +class ValueOrFieldCPPType : public CPPType { + private: + const CPPType &base_type_; + void (*construct_from_value_)(void *dst, const void *value); + void (*construct_from_field_)(void *dst, GField field); + const void *(*get_value_ptr_)(const void *value_or_field); + const GField *(*get_field_ptr_)(const void *value_or_field); + bool (*is_field_)(const void *value_or_field); + GField (*as_field_)(const void *value_or_field); + + public: + template<typename T> + ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name) + : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name), + base_type_(CPPType::get<T>()) + { + construct_from_value_ = [](void *dst, const void *value_or_field) { + new (dst) ValueOrField<T>(*(const T *)value_or_field); + }; + construct_from_field_ = [](void *dst, GField field) { + new (dst) ValueOrField<T>(Field<T>(std::move(field))); + }; + get_value_ptr_ = [](const void *value_or_field) { + return (const void *)&((ValueOrField<T> *)value_or_field)->value; + }; + get_field_ptr_ = [](const void *value_or_field) -> const GField * { + return &((ValueOrField<T> *)value_or_field)->field; + }; + is_field_ = [](const void *value_or_field) { + return ((ValueOrField<T> *)value_or_field)->is_field(); + }; + as_field_ = [](const void *value_or_field) -> GField { + return ((ValueOrField<T> *)value_or_field)->as_field(); + }; + } + + const CPPType &base_type() const + { + return base_type_; + } + + void construct_from_value(void *dst, const void *value) const + { + construct_from_value_(dst, value); + } + + void construct_from_field(void *dst, GField field) const + { + construct_from_field_(dst, field); + } + + const void *get_value_ptr(const void *value_or_field) const + { + return get_value_ptr_(value_or_field); + } + + void *get_value_ptr(void *value_or_field) const + { + /* Use `const_cast` to avoid duplicating the callback for the non-const case. */ + return const_cast<void *>(get_value_ptr_(value_or_field)); + } + + const GField *get_field_ptr(const void *value_or_field) const + { + return get_field_ptr_(value_or_field); + } + + bool is_field(const void *value_or_field) const + { + return is_field_(value_or_field); + } + + GField as_field(const void *value_or_field) const + { + return as_field_(value_or_field); + } +}; + } // namespace blender::fn #define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \ @@ -69,4 +147,13 @@ class FieldCPPType : public CPPType { static blender::fn::FieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \ return cpp_type; \ + } \ + template<> \ + const blender::fn::CPPType & \ + blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \ + { \ + static blender::fn::ValueOrFieldCPPType cpp_type{ \ + blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \ + STRINGIFY(DEBUG_NAME##OrValue)}; \ + return cpp_type; \ } diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index 179e85671f8..57efa1b5ba9 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -125,8 +125,7 @@ template<typename T> class GVectorArray_TypedMutableRef { void extend(const int64_t index, const VArray<T> &values) { - GVArray_For_VArray<T> array{values}; - this->extend(index, array); + vector_array_->extend(index, values); } MutableSpan<T> operator[](const int64_t index) diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index 8aad017e68b..b822f3a7c33 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -23,8 +23,7 @@ * the data type is only known at runtime. */ -#include <optional> - +#include "BLI_timeit.hh" #include "BLI_virtual_array.hh" #include "FN_generic_array.hh" @@ -32,940 +31,845 @@ namespace blender::fn { -template<typename T> class GVArray_Typed; -template<typename T> class GVMutableArray_Typed; +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl and #GVMutableArrayImpl. + * \{ */ class GVArray; +class GVArrayImpl; class GVMutableArray; +class GVMutableArrayImpl; -using GVArrayPtr = std::unique_ptr<GVArray>; -using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>; - -/* A generically typed version of `VArray<T>`. */ -class GVArray { +/* A generically typed version of #VArrayImpl. */ +class GVArrayImpl { protected: const CPPType *type_; int64_t size_; public: - GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size) - { - BLI_assert(size_ >= 0); - } + GVArrayImpl(const CPPType &type, const int64_t size); + virtual ~GVArrayImpl() = default; - virtual ~GVArray() = default; + const CPPType &type() const; - const CPPType &type() const - { - return *type_; - } + int64_t size() const; - int64_t size() const - { - return size_; - } + virtual void get(const int64_t index, void *r_value) const; + virtual void get_to_uninitialized(const int64_t index, void *r_value) const = 0; - bool is_empty() const - { - return size_ == 0; - } + virtual bool is_span() const; + virtual GSpan get_internal_span() const; - /* Copies the value at the given index into the provided storage. The `r_value` pointer is - * expected to point to initialized memory. */ - void get(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_impl(index, r_value); - } + virtual bool is_single() const; + virtual void get_internal_single(void *UNUSED(r_value)) const; - /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ - void get_to_uninitialized(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_to_uninitialized_impl(index, r_value); - } + virtual void materialize(const IndexMask mask, void *dst) const; + virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } + virtual bool try_assign_VArray(void *varray) const; + virtual bool may_have_ownership() const; +}; - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - GSpan get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return GSpan(*type_); - } - return this->get_internal_span_impl(); - } +/* A generic version of #VMutableArrayImpl. */ +class GVMutableArrayImpl : public GVArrayImpl { + public: + GVMutableArrayImpl(const CPPType &type, const int64_t size); - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } + virtual void set_by_copy(const int64_t index, const void *value); + virtual void set_by_relocate(const int64_t index, void *value); + virtual void set_by_move(const int64_t index, void *value) = 0; - /* Copies the value that is used for every element into `r_value`, which is expected to point to - * initialized memory. This invokes undefined behavior if the virtual array would not return the - * same value for every index. */ - void get_internal_single(void *r_value) const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - this->get(0, r_value); - return; - } - this->get_internal_single_impl(r_value); - } + virtual void set_all(const void *src); - /* Same as `get_internal_single`, but `r_value` points to initialized memory. */ - void get_internal_single_to_uninitialized(void *r_value) const - { - type_->default_construct(r_value); - this->get_internal_single(r_value); - } + virtual bool try_assign_VMutableArray(void *varray) const; +}; - void materialize(void *dst) const; - void materialize(const IndexMask mask, void *dst) const; +/** \} */ - void materialize_to_uninitialized(void *dst) const; - void materialize_to_uninitialized(const IndexMask mask, void *dst) const; +/* -------------------------------------------------------------------- */ +/** \name #GVArray and #GVMutableArray + * \{ */ - template<typename T> const VArray<T> *try_get_internal_varray() const - { - BLI_assert(type_->is<T>()); - return (const VArray<T> *)this->try_get_internal_varray_impl(); - } +namespace detail { +struct GVArrayAnyExtraInfo { + const GVArrayImpl *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; }; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVArray_Typed<T> typed() const - { - return GVArray_Typed<T>(*this); - } + template<typename StorageT> static GVArrayAnyExtraInfo get(); +}; +} // namespace detail - GVArrayPtr shallow_copy() const; +class GVMutableArray; +/** + * Utility class to reduce code duplication between #GVArray and #GVMutableArray. + * It pretty much follows #VArrayCommon. Don't use this class outside of this header. + */ +class GVArrayCommon { protected: - virtual void get_impl(const int64_t index, void *r_value) const; - virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0; + /** + * See #VArrayCommon for more information. The inline buffer is a bit larger here, because + * generic virtual array implementations often require a bit more space than typed ones. + */ + using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>; - virtual bool is_span_impl() const; - virtual GSpan get_internal_span_impl() const; + const GVArrayImpl *impl_ = nullptr; + Storage storage_; - virtual bool is_single_impl() const; - virtual void get_internal_single_impl(void *UNUSED(r_value)) const; + protected: + GVArrayCommon(); + GVArrayCommon(const GVArrayCommon &other); + GVArrayCommon(GVArrayCommon &&other) noexcept; + GVArrayCommon(const GVArrayImpl *impl); + GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl); + ~GVArrayCommon(); - virtual void materialize_impl(const IndexMask mask, void *dst) const; - virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const; + template<typename ImplT, typename... Args> void emplace(Args &&...args); - virtual const void *try_get_internal_varray_impl() const; -}; + void copy_from(const GVArrayCommon &other); + void move_from(GVArrayCommon &&other) noexcept; + + const GVArrayImpl *impl_from_storage() const; -/* Similar to GVArray, but supports changing the elements in the virtual array. */ -class GVMutableArray : public GVArray { public: - GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + const CPPType &type() const; + operator bool() const; - void set_by_copy(const int64_t index, const void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_copy_impl(index, value); - } + int64_t size() const; + bool is_empty() const; + IndexRange index_range() const; - void set_by_move(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_move_impl(index, value); - } + template<typename T> bool try_assign_VArray(VArray<T> &varray) const; + bool may_have_ownership() const; - void set_by_relocate(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_relocate_impl(index, value); - } + void materialize(void *dst) const; + void materialize(const IndexMask mask, void *dst) const; - GMutableSpan get_internal_span() - { - BLI_assert(this->is_span()); - GSpan span = static_cast<const GVArray *>(this)->get_internal_span(); - return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); - } + void materialize_to_uninitialized(void *dst) const; + void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - template<typename T> VMutableArray<T> *try_get_internal_mutable_varray() - { - BLI_assert(type_->is<T>()); - return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl(); - } + bool is_span() const; + GSpan get_internal_span() const; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVMutableArray_Typed<T> typed() - { - return GVMutableArray_Typed<T>(*this); - } + bool is_single() const; + void get_internal_single(void *r_value) const; + void get_internal_single_to_uninitialized(void *r_value) const; - void fill(const void *value); + void get(const int64_t index, void *r_value) const; + void get_to_uninitialized(const int64_t index, void *r_value) const; +}; - /* Copy the values from the source buffer to all elements in the virtual array. */ - void set_all(const void *src) - { - this->set_all_impl(src); - } +/** Generic version of #VArray. */ +class GVArray : public GVArrayCommon { + private: + friend GVMutableArray; - protected: - virtual void set_by_copy_impl(const int64_t index, const void *value); - virtual void set_by_relocate_impl(const int64_t index, void *value); - virtual void set_by_move_impl(const int64_t index, void *value) = 0; + public: + GVArray() = default; - virtual void set_all_impl(const void *src); + GVArray(const GVArray &other); + GVArray(GVArray &&other) noexcept; + GVArray(const GVArrayImpl *impl); + GVArray(std::shared_ptr<const GVArrayImpl> impl); - virtual void *try_get_internal_mutable_varray_impl(); -}; + template<typename T> GVArray(const VArray<T> &varray); + template<typename T> VArray<T> typed() const; -class GVArray_For_GSpan : public GVArray { - protected: - const void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVArray For(Args &&...args); - public: - GVArray_For_GSpan(const GSpan span) - : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) - { - } + static GVArray ForSingle(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleRef(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleDefault(const CPPType &type, const int64_t size); + static GVArray ForSpan(GSpan span); + static GVArray ForGArray(GArray<> array); + static GVArray ForEmpty(const CPPType &type); - protected: - GVArray_For_GSpan(const CPPType &type, const int64_t size) - : GVArray(type, size), element_size_(type.size()) - { - } + GVArray slice(IndexRange slice) const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVArray &operator=(const GVArray &other); + GVArray &operator=(GVArray &&other) noexcept; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; + const GVArrayImpl *get_implementation() const + { + return impl_; + } }; -class GVArray_For_Empty : public GVArray { +/** Generic version of #VMutableArray. */ +class GVMutableArray : public GVArrayCommon { public: - GVArray_For_Empty(const CPPType &type) : GVArray(type, 0) - { - } + GVMutableArray() = default; + GVMutableArray(const GVMutableArray &other); + GVMutableArray(GVMutableArray &&other) noexcept; + GVMutableArray(GVMutableArrayImpl *impl); + GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl); - protected: - void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override - { - BLI_assert(false); - } -}; + template<typename T> GVMutableArray(const VMutableArray<T> &varray); + template<typename T> VMutableArray<T> typed() const; -class GVMutableArray_For_GMutableSpan : public GVMutableArray { - protected: - void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args); - public: - GVMutableArray_For_GMutableSpan(const GMutableSpan span) - : GVMutableArray(span.type(), span.size()), - data_(span.data()), - element_size_(span.type().size()) - { - } + static GVMutableArray ForSpan(GMutableSpan span); - protected: - GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size) - : GVMutableArray(type, size), element_size_(type.size()) - { - } + operator GVArray() const &; + operator GVArray() &&noexcept; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVMutableArray &operator=(const GVMutableArray &other); + GVMutableArray &operator=(GVMutableArray &&other) noexcept; - void set_by_copy_impl(const int64_t index, const void *value) override; - void set_by_move_impl(const int64_t index, void *value) override; - void set_by_relocate_impl(const int64_t index, void *value) override; + GMutableSpan get_internal_span() const; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; -}; + template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const; -/* Generic virtual array where each element has the same value. The value is not owned. */ -class GVArray_For_SingleValueRef : public GVArray { - protected: - const void *value_ = nullptr; + void set_by_copy(const int64_t index, const void *value); + void set_by_move(const int64_t index, void *value); + void set_by_relocate(const int64_t index, void *value); - public: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) - : GVArray(type, size), value_(value) - { - } + void fill(const void *value); + void set_all(const void *src); - protected: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + GVMutableArrayImpl *get_implementation() const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + private: + GVMutableArrayImpl *get_impl() const; +}; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; +/** \} */ - bool is_single_impl() const override; - void get_internal_single_impl(void *r_value) const override; +/* -------------------------------------------------------------------- */ +/** \name #GVArray_GSpan and #GVMutableArray_GSpan. + * \{ */ + +/* A generic version of VArray_Span. */ +class GVArray_GSpan : public GSpan { + private: + GVArray varray_; + void *owned_data_ = nullptr; + + public: + GVArray_GSpan(GVArray varray); + ~GVArray_GSpan(); }; -/* Same as GVArray_For_SingleValueRef, but the value is owned. */ -class GVArray_For_SingleValue : public GVArray_For_SingleValueRef { +/* A generic version of VMutableArray_Span. */ +class GVMutableArray_GSpan : public GMutableSpan { + private: + GVMutableArray varray_; + void *owned_data_ = nullptr; + bool save_has_been_called_ = false; + bool show_not_saved_warning_ = true; + public: - GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value); - ~GVArray_For_SingleValue(); + GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true); + ~GVMutableArray_GSpan(); + + void save(); + void disable_not_applied_warning(); }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversions between generic and typed virtual arrays. + * \{ */ + /* Used to convert a typed virtual array into a generic one. */ -template<typename T> class GVArray_For_VArray : public GVArray { +template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl { protected: - const VArray<T> *varray_ = nullptr; + VArray<T> varray_; public: - GVArray_For_VArray(const VArray<T> &varray) - : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVArrayImpl_For_VArray(VArray<T> varray) + : GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); + return GSpan(varray_.get_internal_span()); } - GSpan get_internal_span_impl() const override + bool is_single() const override { - return GSpan(varray_->get_internal_span()); + return varray_.is_single(); } - bool is_single_impl() const override + void get_internal_single(void *r_value) const override { - return varray_->is_single(); + *(T *)r_value = varray_.get_internal_single(); } - void get_internal_single_impl(void *r_value) const override + void materialize(const IndexMask mask, void *dst) const override { - *(T *)r_value = varray_->get_internal_single(); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + bool try_assign_VArray(void *varray) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + *(VArray<T> *)varray = varray_; + return true; } - const void *try_get_internal_varray_impl() const override - { - return varray_; - } -}; - -class GVArray_For_GArray : public GVArray_For_GSpan { - protected: - GArray<> array_; - - public: - GVArray_For_GArray(GArray<> array) : GVArray_For_GSpan(array.as_span()), array_(std::move(array)) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; /* Used to convert any generic virtual array into a typed one. */ -template<typename T> class VArray_For_GVArray : public VArray<T> { +template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> { protected: - const GVArray *varray_ = nullptr; + GVArray varray_; public: - VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray) + VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray)) { - BLI_assert(varray_->type().template is<T>()); + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } protected: - VArray_For_GVArray(const int64_t size) : VArray<T>(size) - { - } - - T get_impl(const int64_t index) const override + T get(const int64_t index) const override { T value; - varray_->get(index, &value); + varray_.get(index, &value); return value; } - bool is_span_impl() const override + bool is_span() const override { - return varray_->is_span(); + return varray_.is_span(); } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { - return varray_->get_internal_span().template typed<T>(); + return varray_.get_internal_span().template typed<T>(); } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - T get_internal_single_impl() const override + T get_internal_single() const override { T value; - varray_->get_internal_single(&value); + varray_.get_internal_single(&value); return value; } -}; - -/* Used to convert an generic mutable virtual array into a typed one. */ -template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> { - protected: - GVMutableArray *varray_ = nullptr; - - public: - VMutableArray_For_GVMutableArray(GVMutableArray &varray) - : VMutableArray<T>(varray.size()), varray_(&varray) - { - BLI_assert(varray.type().template is<T>()); - } - - VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size) - { - } - - private: - T get_impl(const int64_t index) const override - { - T value; - varray_->get(index, &value); - return value; - } - - void set_impl(const int64_t index, T value) override - { - varray_->set_by_relocate(index, &value); - } - - bool is_span_impl() const override - { - return varray_->is_span(); - } - Span<T> get_internal_span_impl() const override + bool try_assign_GVArray(GVArray &varray) const override { - return varray_->get_internal_span().template typed<T>(); + varray = varray_; + return true; } - bool is_single_impl() const override + bool may_have_ownership() const override { - return varray_->is_single(); - } - - T get_internal_single_impl() const override - { - T value; - varray_->get_internal_single(&value); - return value; + return varray_.may_have_ownership(); } }; /* Used to convert any typed virtual mutable array into a generic one. */ -template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray { +template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl { protected: - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: - GVMutableArray_For_VMutableArray(VMutableArray<T> &varray) - : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray) + : GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); - } - - GSpan get_internal_span_impl() const override - { - Span<T> span = varray_->get_internal_span(); + Span<T> span = varray_.get_internal_span(); return span; } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - void get_internal_single_impl(void *r_value) const override + void get_internal_single(void *r_value) const override { - *(T *)r_value = varray_->get_internal_single(); + *(T *)r_value = varray_.get_internal_single(); } - void set_by_copy_impl(const int64_t index, const void *value) override + void set_by_copy(const int64_t index, const void *value) override { const T &value_ = *(const T *)value; - varray_->set(index, value_); + varray_.set(index, value_); } - void set_by_relocate_impl(const int64_t index, void *value) override + void set_by_relocate(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); value_.~T(); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); } - void set_all_impl(const void *src) override + void set_all(const void *src) override { - varray_->set_all(Span((T *)src, size_)); + varray_.set_all(Span((T *)src, size_)); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - const void *try_get_internal_varray_impl() const override + bool try_assign_VArray(void *varray) const override { - return (const VArray<T> *)varray_; + *(VArray<T> *)varray = varray_; + return true; } - void *try_get_internal_mutable_varray_impl() override + bool try_assign_VMutableArray(void *varray) const override { - return varray_; + *(VMutableArray<T> *)varray = varray_; + return true; } -}; - -/* A generic version of VArray_Span. */ -class GVArray_GSpan : public GSpan { - private: - const GVArray &varray_; - void *owned_data_ = nullptr; - - public: - GVArray_GSpan(const GVArray &varray); - ~GVArray_GSpan(); -}; - -/* A generic version of VMutableArray_Span. */ -class GVMutableArray_GSpan : public GMutableSpan { - private: - GVMutableArray &varray_; - void *owned_data_ = nullptr; - bool save_has_been_called_ = false; - bool show_not_saved_warning_ = true; - - public: - GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true); - ~GVMutableArray_GSpan(); - - void save(); - void disable_not_applied_warning(); -}; - -/* Similar to GVArray_GSpan, but the resulting span is typed. */ -template<typename T> class GVArray_Span : public Span<T> { - private: - GVArray_GSpan varray_gspan_; - public: - GVArray_Span(const GVArray &varray) : varray_gspan_(varray) + bool may_have_ownership() const override { - BLI_assert(varray.type().is<T>()); - this->data_ = (const T *)varray_gspan_.data(); - this->size_ = varray_gspan_.size(); + return varray_.may_have_ownership(); } }; -template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> { - private: - VArrayPtr<T> owned_varray_; +/* Used to convert an generic mutable virtual array into a typed one. */ +template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> { + protected: + GVMutableArray varray_; public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVArray_For_OwnedVArray(VArrayPtr<T> varray) - : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray)) + VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray) + : VMutableArrayImpl<T>(varray.size()), varray_(varray) { + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } -}; -template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> { private: - GVArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VArray_For_OwnedGVArray(GVArrayPtr varray) - : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray)) + T get(const int64_t index) const override { + T value; + varray_.get(index, &value); + return value; } -}; -template<typename T> -class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayPtr<T> owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray) - : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray)) + void set(const int64_t index, T value) override { + varray_.set_by_relocate(index, &value); } -}; -template<typename T> -class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> { - private: - GVMutableArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray) - : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray)) + bool is_span() const override { + return varray_.is_span(); } -}; - -/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give - * the compiler more opportunity to optimize the generic virtual array. */ -template<typename T, typename VArrayT> -class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> { - private: - VArrayT embedded_varray_; - public: - template<typename... Args> - GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args) - : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + Span<T> get_internal_span() const override { - this->varray_ = &embedded_varray_; + return varray_.get_internal_span().template typed<T>(); } -}; -/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */ -template<typename T, typename VMutableArrayT> -class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayT embedded_varray_; - - public: - template<typename... Args> - GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args) - : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + bool is_single() const override { - this->varray_ = &embedded_varray_; + return varray_.is_single(); } -}; -/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */ -template<typename Container, typename T = typename Container::value_type> -class GVArray_For_ArrayContainer - : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> { - public: - GVArray_For_ArrayContainer(Container container) - : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>( - container.size(), std::move(container)) + T get_internal_single() const override { + T value; + varray_.get_internal_single(&value); + return value; } -}; -/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class GVArray_For_DerivedSpan - : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> { - public: - GVArray_For_DerivedSpan(const Span<StructT> data) - : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( - data.size(), data) + bool try_assign_GVArray(GVArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class GVMutableArray_For_DerivedSpan - : public GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> { - public: - GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data) + bool try_assign_GVMutableArray(GVMutableArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VArray_For_Span, but for a generic virtual array. */ -template<typename T> -class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> { - public: - GVArray_For_Span(const Span<T> data) - : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; -/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */ -template<typename T> -class GVMutableArray_For_MutableSpan - : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> { +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan. + * \{ */ + +class GVArrayImpl_For_GSpan : public GVArrayImpl { + protected: + const void *data_ = nullptr; + const int64_t element_size_; + public: - GVMutableArray_For_MutableSpan(const MutableSpan<T> data) - : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(), - data) - { - } + GVArrayImpl_For_GSpan(const GSpan span); + + protected: + GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size); + + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; + + bool is_span() const override; + GSpan get_internal_span() const override; }; -/** - * Utility class to create the "best" typed virtual array for a given generic virtual array. - * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional - * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is - * just a span or single value). - * - * This is not a virtual array itself, but is used to get a virtual array. - */ -template<typename T> class GVArray_Typed { - private: - const VArray<T> *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<VArray_For_Span<T>> varray_span_; - std::optional<VArray_For_Single<T>> varray_single_; - std::optional<VArray_For_GVArray<T>> varray_any_; - GVArrayPtr owned_gvarray_; +class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl { + protected: + void *data_ = nullptr; + const int64_t element_size_; public: - explicit GVArray_Typed(const GVArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (gvarray.is_single()) { - T single_value; - gvarray.get_internal_single(&single_value); - varray_single_.emplace(single_value, gvarray.size()); - varray_ = &*varray_single_; - } - else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } + GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span); - /* Same as the constructor above, but also takes ownership of the passed in virtual array. */ - explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } + protected: + GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size); - const VArray<T> &operator*() const - { - return *varray_; - } + public: + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; - const VArray<T> *operator->() const - { - return varray_; - } + void set_by_copy(const int64_t index, const void *value) override; + void set_by_move(const int64_t index, void *value) override; + void set_by_relocate(const int64_t index, void *value) override; - /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is - * used within an expression. */ - operator const VArray<T> &() const - { - return *varray_; - } + bool is_span() const override; + GSpan get_internal_span() const override; +}; - T operator[](const int64_t index) const - { - return varray_->get(index); - } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayImpl. + * \{ */ + +inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size) + : type_(&type), size_(size) +{ + BLI_assert(size_ >= 0); +} + +inline const CPPType &GVArrayImpl::type() const +{ + return *type_; +} + +inline int64_t GVArrayImpl::size() const +{ + return size_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArrayImpl. + * \{ */ + +inline void GVMutableArray::set_by_copy(const int64_t index, const void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_copy(index, value); +} + +inline void GVMutableArray::set_by_move(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_move(index, value); +} + +inline void GVMutableArray::set_by_relocate(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_relocate(index, value); +} - int64_t size() const - { - return varray_->size(); +template<typename T> +inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return this->get_impl()->try_assign_VMutableArray(&varray); +} + +inline GVMutableArrayImpl *GVMutableArray::get_impl() const +{ + return (GVMutableArrayImpl *)impl_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayCommon. + * \{ */ + +template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } +} + +/* Copies the value at the given index into the provided storage. The `r_value` pointer is + * expected to point to initialized memory. */ +inline void GVArrayCommon::get(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get(index, r_value); +} + +/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ +inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get_to_uninitialized(index, r_value); +} + +template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return impl_->try_assign_VArray(&varray); +} + +inline const CPPType &GVArrayCommon::type() const +{ + return impl_->type(); +} + +inline GVArrayCommon::operator bool() const +{ + return impl_ != nullptr; +} + +inline int64_t GVArrayCommon::size() const +{ + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); +} + +inline bool GVArrayCommon::is_empty() const +{ + return this->size() == 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArray. + * \{ */ + +namespace detail { +template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get() +{ + static_assert(std::is_base_of_v<GVArrayImpl, StorageT> || + std::is_same_v<StorageT, const GVArrayImpl *> || + std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>); + + if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) { + return {[](const void *buffer) { + return static_cast<const GVArrayImpl *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } +} +} // namespace detail + +template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + GVArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} + +template<typename T> inline GVArray::GVArray(const VArray<T> &varray) +{ + if (!varray) { + return; + } + if (varray.try_assign_GVArray(*this)) { + return; + } + /* Need to check this before the span/single special cases, because otherwise we might loose + * ownership to the referenced data when #varray goes out of scope. */ + if (varray.may_have_ownership()) { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } + else if (varray.is_span()) { + Span<T> data = varray.get_internal_span(); + *this = GVArray::ForSpan(data); + } + else if (varray.is_single()) { + T value = varray.get_internal_single(); + *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value); + } + else { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } +} + +template<typename T> inline VArray<T> GVArray::typed() const +{ + if (!*this) { + return {}; + } + BLI_assert(impl_->type().is<T>()); + VArray<T> varray; + if (this->try_assign_VArray(varray)) { + return varray; + } + if (this->may_have_ownership()) { + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); + } + if (this->is_span()) { + const Span<T> span = this->get_internal_span().typed<T>(); + return VArray<T>::ForSpan(span); } - - IndexRange index_range() const - { - return IndexRange(this->size()); + if (this->is_single()) { + T value; + this->get_internal_single(&value); + return VArray<T>::ForSingle(value, this->size()); } -}; + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); +} -/* Same as GVArray_Typed, but for mutable virtual arrays. */ -template<typename T> class GVMutableArray_Typed { - private: - VMutableArray<T> *varray_; - std::optional<VMutableArray_For_MutableSpan<T>> varray_span_; - std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_; - GVMutableArrayPtr owned_gvarray_; +/** \} */ - public: - explicit GVMutableArray_Typed(GVMutableArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GMutableSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArray. + * \{ */ - explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } +template<typename ImplT, typename... Args> +inline GVMutableArray GVMutableArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>); + GVMutableArray varray; + varray.emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} - VMutableArray<T> &operator*() - { - return *varray_; +template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray) +{ + if (!varray) { + return; } - - VMutableArray<T> *operator->() - { - return varray_; + if (varray.try_assign_GVMutableArray(*this)) { + return; } - - operator VMutableArray<T> &() - { - return *varray_; + if (varray.may_have_ownership()) { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } - - T operator[](const int64_t index) const - { - return varray_->get(index); + else if (varray.is_span()) { + MutableSpan<T> data = varray.get_internal_span(); + *this = GVMutableArray::ForSpan(data); } - - int64_t size() const - { - return varray_->size(); + else { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } -}; - -class GVArray_For_SlicedGVArray : public GVArray { - protected: - const GVArray &varray_; - int64_t offset_; +} - public: - GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice) - : GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start()) - { - BLI_assert(slice.one_after_last() <= varray.size()); +template<typename T> inline VMutableArray<T> GVMutableArray::typed() const +{ + if (!*this) { + return {}; } - - /* TODO: Add #materialize method. */ - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; -}; - -/** - * Utility class to create the "best" sliced virtual array. - */ -class GVArray_Slice { - private: - const GVArray *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<GVArray_For_GSpan> varray_span_; - std::optional<GVArray_For_SlicedGVArray> varray_any_; - - public: - GVArray_Slice(const GVArray &varray, const IndexRange slice); - - const GVArray &operator*() - { - return *varray_; + BLI_assert(this->type().is<T>()); + VMutableArray<T> varray; + if (this->try_assign_VMutableArray(varray)) { + return varray; } - - const GVArray *operator->() - { - return varray_; + if (this->may_have_ownership()) { + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); } - - operator const GVArray &() - { - return *varray_; + if (this->is_span()) { + const MutableSpan<T> span = this->get_internal_span().typed<T>(); + return VMutableArray<T>::ForSpan(span); } -}; + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); +} + +/** \} */ } // namespace blender::fn diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh index 4155a55a801..b80e21eaef1 100644 --- a/source/blender/functions/FN_generic_virtual_vector_array.hh +++ b/source/blender/functions/FN_generic_virtual_vector_array.hh @@ -100,31 +100,31 @@ class GVVectorArray { } }; -class GVArray_For_GVVectorArrayIndex : public GVArray { +class GVArray_For_GVVectorArrayIndex : public GVArrayImpl { private: const GVVectorArray &vector_array_; const int64_t index_; public: GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index) - : GVArray(vector_array.type(), vector_array.get_vector_size(index)), + : GVArrayImpl(vector_array.type(), vector_array.get_vector_size(index)), vector_array_(vector_array), index_(index) { } protected: - void get_impl(const int64_t index_in_vector, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override; + void get(const int64_t index_in_vector, void *r_value) const override; + void get_to_uninitialized(const int64_t index_in_vector, void *r_value) const override; }; class GVVectorArray_For_SingleGVArray : public GVVectorArray { private: - const GVArray &array_; + GVArray varray_; public: - GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size) - : GVVectorArray(array.type(), size), array_(array) + GVVectorArray_For_SingleGVArray(GVArray varray, const int64_t size) + : GVVectorArray(varray.type(), size), varray_(std::move(varray)) { } diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh index 98788025558..3059fe59ca7 100644 --- a/source/blender/functions/FN_multi_function.hh +++ b/source/blender/functions/FN_multi_function.hh @@ -97,6 +97,8 @@ class MultiFunction { return signature_ref_->function_name; } + virtual std::string debug_name() const; + bool depends_on_context() const { return signature_ref_->depends_on_context; @@ -131,8 +133,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask { } -extern const MultiFunction &dummy_multi_function; - namespace multi_function_types { using fn::CPPType; using fn::GMutableSpan; diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 0ce05cbca30..eaf9e5ce70f 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio MFSignature signature_; public: - CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio } template<typename ElementFuncT> - CustomMF_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn)) { } @@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn)) { } @@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn)) { } @@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn)) { } @@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { MFSignature signature_; public: - CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_mutable<Mut1>("Mut1"); @@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SM(StringRef name, ElementFuncT element_fn) + CustomMF_SM(const char *name, ElementFuncT element_fn) : CustomMF_SM(name, CustomMF_SM::create_function(element_fn)) { } @@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti static MFSignature create_signature() { - std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); - MFSignatureBuilder signature{std::move(name)}; + static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); + MFSignatureBuilder signature{name.c_str()}; signature.single_input<From>("Input"); signature.single_output<To>("Output"); return signature.build(); @@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction { template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value)) { MFSignatureBuilder signature{"Constant"}; - std::stringstream ss; - ss << value_; - signature.single_output<T>(ss.str()); + signature.single_output<T>("Value"); signature_ = signature.build(); this->set_signature(&signature_); } @@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction { MFSignature signature_; public: - CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, - Span<MFDataType> output_types); + CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types); void call(IndexMask mask, MFParams params, MFContext context) const override; }; @@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction { MFSignature signature_; public: - CustomMF_GenericCopy(StringRef name, MFDataType data_type); + CustomMF_GenericCopy(MFDataType data_type); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index d187985de9d..5c7e75230f3 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -40,7 +40,7 @@ class MFParamsBuilder { const MFSignature *signature_; IndexMask mask_; int64_t min_array_size_; - Vector<const GVArray *> virtual_arrays_; + Vector<GVArray> virtual_arrays_; Vector<GMutableSpan> mutable_spans_; Vector<const GVVectorArray *> virtual_vector_arrays_; Vector<GVectorArray *> vector_arrays_; @@ -68,24 +68,22 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(CPPType::get<T>(), min_array_size_, value), - expected_name); + GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name); } void add_readonly_single_input(const GSpan span, StringRef expected_name = "") { - this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(span), expected_name); + this->add_readonly_single_input(GVArray::ForSpan(span), expected_name); } void add_readonly_single_input(GPointer value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(*value.type(), min_array_size_, value.get()), - expected_name); + GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name); } - void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "") + void add_readonly_single_input(GVArray varray, StringRef expected_name = "") { - this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name); - BLI_assert(ref.size() >= min_array_size_); - virtual_arrays_.append(&ref); + this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name); + BLI_assert(varray.size() >= min_array_size_); + virtual_arrays_.append(varray); } void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "") @@ -221,16 +219,16 @@ class MFParams { { } - template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "") + template<typename T> VArray<T> readonly_single_input(int param_index, StringRef name = "") { - const GVArray &array = this->readonly_single_input(param_index, name); - return builder_->scope_.construct<GVArray_Typed<T>>(array); + const GVArray &varray = this->readonly_single_input(param_index, name); + return varray.typed<T>(); } const GVArray &readonly_single_input(int param_index, StringRef name = "") { this->assert_correct_param(param_index, name, MFParamType::SingleInput); int data_index = builder_->signature_->data_index(param_index); - return *builder_->virtual_arrays_[data_index]; + return builder_->virtual_arrays_[data_index]; } /** diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh index 9c8b59739b8..b12e3a91210 100644 --- a/source/blender/functions/FN_multi_function_procedure_executor.hh +++ b/source/blender/functions/FN_multi_function_procedure_executor.hh @@ -31,7 +31,7 @@ class MFProcedureExecutor : public MultiFunction { const MFProcedure &procedure_; public: - MFProcedureExecutor(std::string name, const MFProcedure &procedure); + MFProcedureExecutor(const MFProcedure &procedure); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index d05948cc645..3c991bc9c56 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -30,8 +30,15 @@ namespace blender::fn { struct MFSignature { - std::string function_name; - Vector<std::string> param_names; + /** + * The name should be statically allocated so that it lives longer than this signature. This is + * used instead of an #std::string because of the overhead when many functions are created. + * If the name of the function has to be more dynamic for debugging purposes, override + * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is + * actually needed. + */ + const char *function_name; + Vector<const char *> param_names; Vector<MFParamType> param_types; Vector<int> param_data_indices; bool depends_on_context = false; @@ -51,9 +58,9 @@ class MFSignatureBuilder { int vector_array_count_ = 0; public: - MFSignatureBuilder(std::string function_name) + MFSignatureBuilder(const char *function_name) { - signature_.function_name = std::move(function_name); + signature_.function_name = function_name; } MFSignature build() const @@ -63,23 +70,23 @@ class MFSignatureBuilder { /* Input Parameter Types */ - template<typename T> void single_input(StringRef name) + template<typename T> void single_input(const char *name) { this->single_input(name, CPPType::get<T>()); } - void single_input(StringRef name, const CPPType &type) + void single_input(const char *name, const CPPType &type) { this->input(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_input(StringRef name) + template<typename T> void vector_input(const char *name) { this->vector_input(name, CPPType::get<T>()); } - void vector_input(StringRef name, const CPPType &base_type) + void vector_input(const char *name, const CPPType &base_type) { this->input(name, MFDataType::ForVector(base_type)); } - void input(StringRef name, MFDataType data_type) + void input(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Input, data_type)); @@ -96,23 +103,23 @@ class MFSignatureBuilder { /* Output Parameter Types */ - template<typename T> void single_output(StringRef name) + template<typename T> void single_output(const char *name) { this->single_output(name, CPPType::get<T>()); } - void single_output(StringRef name, const CPPType &type) + void single_output(const char *name, const CPPType &type) { this->output(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_output(StringRef name) + template<typename T> void vector_output(const char *name) { this->vector_output(name, CPPType::get<T>()); } - void vector_output(StringRef name, const CPPType &base_type) + void vector_output(const char *name, const CPPType &base_type) { this->output(name, MFDataType::ForVector(base_type)); } - void output(StringRef name, MFDataType data_type) + void output(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Output, data_type)); @@ -129,23 +136,23 @@ class MFSignatureBuilder { /* Mutable Parameter Types */ - template<typename T> void single_mutable(StringRef name) + template<typename T> void single_mutable(const char *name) { this->single_mutable(name, CPPType::get<T>()); } - void single_mutable(StringRef name, const CPPType &type) + void single_mutable(const char *name, const CPPType &type) { this->mutable_(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_mutable(StringRef name) + template<typename T> void vector_mutable(const char *name) { this->vector_mutable(name, CPPType::get<T>()); } - void vector_mutable(StringRef name, const CPPType &base_type) + void vector_mutable(const char *name, const CPPType &base_type) { this->mutable_(name, MFDataType::ForVector(base_type)); } - void mutable_(StringRef name, MFDataType data_type) + void mutable_(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type)); @@ -160,7 +167,7 @@ class MFSignatureBuilder { } } - void add(StringRef name, const MFParamType ¶m_type) + void add(const char *name, const MFParamType ¶m_type) { switch (param_type.interface_type()) { case MFParamType::Input: diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 4de5e71c910..7934490a6d9 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -81,19 +81,18 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields) /** * Retrieves the data from the context that is passed as input into the field. */ -static Vector<const GVArray *> get_field_context_inputs( +static Vector<GVArray> get_field_context_inputs( ResourceScope &scope, const IndexMask mask, const FieldContext &context, const Span<std::reference_wrapper<const FieldInput>> field_inputs) { - Vector<const GVArray *> field_context_inputs; + Vector<GVArray> field_context_inputs; for (const FieldInput &field_input : field_inputs) { - const GVArray *varray = context.get_varray_for_input(field_input, mask, scope); - if (varray == nullptr) { + GVArray varray = context.get_varray_for_input(field_input, mask, scope); + if (!varray) { const CPPType &type = field_input.cpp_type(); - varray = &scope.construct<GVArray_For_SingleValueRef>( - type, mask.min_array_size(), type.default_value()); + varray = GVArray::ForSingleDefault(type, mask.min_array_size()); } field_context_inputs.append(varray); } @@ -105,7 +104,7 @@ static Vector<const GVArray *> get_field_context_inputs( * for different indices. */ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, - Span<const GVArray *> field_context_inputs) + Span<GVArray> field_context_inputs) { Set<GFieldRef> found_fields; Stack<GFieldRef> fields_to_check; @@ -114,8 +113,8 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, * start the tree search at the non-constant input fields and traverse through all fields that * depend on them. */ for (const int i : field_context_inputs.index_range()) { - const GVArray *varray = field_context_inputs[i]; - if (varray->is_single()) { + const GVArray &varray = field_context_inputs[i]; + if (varray.is_single()) { continue; } const FieldInput &field_input = field_tree_info.deduplicated_field_inputs[i]; @@ -238,8 +237,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, if (!already_output_variables.add(variable)) { /* One variable can be output at most once. To output the same value twice, we have to make * a copy first. */ - const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>("copy", - variable->data_type()); + const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type()); variable = builder.add_call<1>(copy_fn, {variable})[0]; } builder.add_output_parameter(*variable); @@ -278,29 +276,42 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the * provided virtual arrays are returned. */ -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays) +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays) { - Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr); + Vector<GVArray> r_varrays(fields_to_evaluate.size()); + Array<bool> is_output_written_to_dst(fields_to_evaluate.size(), false); const int array_size = mask.min_array_size(); + if (mask.is_empty()) { + for (const int i : fields_to_evaluate.index_range()) { + const CPPType &type = fields_to_evaluate[i].cpp_type(); + r_varrays[i] = GVArray::ForEmpty(type); + } + return r_varrays; + } + /* Destination arrays are optional. Create a small utility method to access them. */ - auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * { + auto get_dst_varray = [&](int index) -> GVMutableArray { if (dst_varrays.is_empty()) { - return nullptr; + return {}; + } + const GVMutableArray &varray = dst_varrays[index]; + if (!varray) { + return {}; } - BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size); - return dst_varrays[index]; + BLI_assert(varray.size() >= array_size); + return varray; }; /* Traverse the field tree and prepare some data that is used in later steps. */ FieldTreeInfo field_tree_info = preprocess_field_tree(fields_to_evaluate); /* Get inputs that will be passed into the field when evaluated. */ - Vector<const GVArray *> field_context_inputs = get_field_context_inputs( + Vector<GVArray> field_context_inputs = get_field_context_inputs( scope, mask, context, field_tree_info.deduplicated_field_inputs); /* Finish fields that output an input varray directly. For those we don't have to do any further @@ -312,7 +323,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, } const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input); - const GVArray *varray = field_context_inputs[field_input_index]; + const GVArray &varray = field_context_inputs[field_input_index]; r_varrays[out_index] = varray; } @@ -325,7 +336,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, Vector<GFieldRef> constant_fields_to_evaluate; Vector<int> constant_field_indices; for (const int i : fields_to_evaluate.index_range()) { - if (r_varrays[i] != nullptr) { + if (r_varrays[i]) { /* Already done. */ continue; } @@ -346,7 +357,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, varying_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; + MFProcedureExecutor procedure_executor{procedure}; /* Add multi threading capabilities to the field evaluation. */ const int grain_size = 10000; fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size}; @@ -357,8 +368,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : varying_fields_to_evaluate.index_range()) { @@ -367,9 +378,9 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, const int out_index = varying_field_indices[i]; /* Try to get an existing virtual array that the result should be written into. */ - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); + GVMutableArray dst_varray = get_dst_varray(out_index); void *buffer; - if (output_varray == nullptr || !output_varray->is_span()) { + if (!dst_varray || !dst_varray.is_span()) { /* Allocate a new buffer for the computed result. */ buffer = scope.linear_allocator().allocate(type.size() * array_size, type.alignment()); @@ -379,14 +390,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, [buffer, mask, &type]() { type.destruct_indices(buffer, mask); }); } - r_varrays[out_index] = &scope.construct<GVArray_For_GSpan>( - GSpan{type, buffer, array_size}); + r_varrays[out_index] = GVArray::ForSpan({type, buffer, array_size}); } else { /* Write the result into the existing span. */ - buffer = output_varray->get_internal_span().data(); + buffer = dst_varray.get_internal_span().data(); - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; + is_output_written_to_dst[out_index] = true; } /* Pass output buffer to the procedure executor. */ @@ -403,16 +414,13 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, constant_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; - /* Run the code below even when the mask is empty, so that outputs are properly prepared. - * Higher level code can detect this as well and just skip evaluating the field. */ - const int mask_size = mask.is_empty() ? 0 : 1; - MFParamsBuilder mf_params{procedure_executor, mask_size}; + MFProcedureExecutor procedure_executor{procedure}; + MFParamsBuilder mf_params{procedure_executor, 1}; MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : constant_fields_to_evaluate.index_range()) { @@ -421,55 +429,52 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, /* Allocate memory where the computed value will be stored in. */ void *buffer = scope.linear_allocator().allocate(type.size(), type.alignment()); - if (!type.is_trivially_destructible() && mask_size > 0) { - BLI_assert(mask_size == 1); + if (!type.is_trivially_destructible()) { /* Destruct value in the end. */ scope.add_destruct_call([buffer, &type]() { type.destruct(buffer); }); } /* Pass output buffer to the procedure executor. */ - mf_params.add_uninitialized_single_output({type, buffer, mask_size}); + mf_params.add_uninitialized_single_output({type, buffer, 1}); /* Create virtual array that can be used after the procedure has been executed below. */ const int out_index = constant_field_indices[i]; - r_varrays[out_index] = &scope.construct<GVArray_For_SingleValueRef>( - type, array_size, buffer); + r_varrays[out_index] = GVArray::ForSingleRef(type, array_size, buffer); } - procedure_executor.call(IndexRange(mask_size), mf_params, mf_context); + procedure_executor.call(IndexRange(1), mf_params, mf_context); } - /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has - * written the computed data in the right place already. */ + /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above + * has written the computed data in the right place already. */ if (!dst_varrays.is_empty()) { for (const int out_index : fields_to_evaluate.index_range()) { - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); - if (output_varray == nullptr) { + GVMutableArray dst_varray = get_dst_varray(out_index); + if (!dst_varray) { /* Caller did not provide a destination for this output. */ continue; } - const GVArray *computed_varray = r_varrays[out_index]; - BLI_assert(computed_varray->type() == output_varray->type()); - if (output_varray == computed_varray) { + const GVArray &computed_varray = r_varrays[out_index]; + BLI_assert(computed_varray.type() == dst_varray.type()); + if (is_output_written_to_dst[out_index]) { /* The result has been written into the destination provided by the caller already. */ continue; } /* Still have to copy over the data in the destination provided by the caller. */ - if (output_varray->is_span()) { + if (dst_varray.is_span()) { /* Materialize into a span. */ - computed_varray->materialize_to_uninitialized(mask, - output_varray->get_internal_span().data()); + computed_varray.materialize_to_uninitialized(mask, dst_varray.get_internal_span().data()); } else { /* Slower materialize into a different structure. */ - const CPPType &type = computed_varray->type(); + const CPPType &type = computed_varray.type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); for (const int i : mask) { - computed_varray->get_to_uninitialized(i, buffer); - output_varray->set_by_relocate(i, buffer); + computed_varray.get_to_uninitialized(i, buffer); + dst_varray.set_by_relocate(i, buffer); } } - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; } } return r_varrays; @@ -485,8 +490,8 @@ void evaluate_constant_field(const GField &field, void *r_value) ResourceScope scope; FieldContext context; - Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); - varrays[0]->get_to_uninitialized(0, r_value); + Vector<GVArray> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); + varrays[0].get_to_uninitialized(0, r_value); } /** @@ -506,15 +511,21 @@ GField make_field_constant_if_possible(GField field) const CPPType &type = field.cpp_type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); evaluate_constant_field(field, buffer); - auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true); + GField new_field = make_constant_field(type, buffer); type.destruct(buffer); + return new_field; +} + +GField make_constant_field(const CPPType &type, const void *value) +{ + auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true); auto operation = std::make_shared<FieldOperation>(std::move(constant_fn)); - return GField{operation, 0}; + return GField{std::move(operation), 0}; } -const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const +GVArray FieldContext::get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const { /* By default ask the field input to create the varray. Another field context might overwrite * the context here. */ @@ -526,17 +537,15 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index") category_ = Category::Generated; } -GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope) +GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope)) { auto index_func = [](int i) { return i; }; - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } -const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const +GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &scope) const { /* TODO: Investigate a similar method to IndexRange::as_span() */ return get_index_varray(mask, scope); @@ -631,27 +640,26 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection) return indices; } -int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst) +int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(&dst); + dst_varrays_.append(dst); output_pointer_infos_.append({}); return field_index; } int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), GVMutableArray::ForSpan(dst)); } -int FieldEvaluator::add(GField field, const GVArray **varray_ptr) +int FieldEvaluator::add(GField field, GVArray *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); dst_varrays_.append(nullptr); output_pointer_infos_.append(OutputPointerInfo{ varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { - *(const GVArray **)dst = &varray; + *(GVArray *)dst = varray; }}); return field_index; } @@ -676,7 +684,7 @@ void FieldEvaluator::evaluate() for (const int i : fields_to_evaluate_.index_range()) { OutputPointerInfo &info = output_pointer_infos_[i]; if (info.dst != nullptr) { - info.set(info.dst, *evaluated_varrays_[i], scope_); + info.set(info.dst, evaluated_varrays_[i], scope_); } } is_evaluated_ = true; @@ -684,17 +692,16 @@ void FieldEvaluator::evaluate() IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<bool> typed_varray{varray}; + VArray<bool> varray = this->get_evaluated(field_index).typed<bool>(); - if (typed_varray->is_single()) { - if (typed_varray->get_internal_single()) { - return IndexRange(typed_varray.size()); + if (varray.is_single()) { + if (varray.get_internal_single()) { + return IndexRange(varray.size()); } return IndexRange(0); } - return scope_.add_value(indices_from_selection(*typed_varray)).as_span(); + return scope_.add_value(indices_from_selection(varray)).as_span(); } } // namespace blender::fn diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc index ec95a283919..0d478007a5a 100644 --- a/source/blender/functions/intern/generic_vector_array.cc +++ b/source/blender/functions/intern/generic_vector_array.cc @@ -60,15 +60,14 @@ void GVectorArray::extend(const int64_t index, const GVArray &values) void GVectorArray::extend(const int64_t index, const GSpan values) { - GVArray_For_GSpan varray{values}; - this->extend(index, varray); + this->extend(index, GVArray::ForSpan(values)); } void GVectorArray::extend(IndexMask mask, const GVVectorArray &values) { for (const int i : mask) { GVArray_For_GVVectorArrayIndex array{values, i}; - this->extend(i, array); + this->extend(i, GVArray(&array)); } } diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc index ea54f1e7c00..1fe1c2fc229 100644 --- a/source/blender/functions/intern/generic_virtual_array.cc +++ b/source/blender/functions/intern/generic_virtual_array.cc @@ -19,52 +19,10 @@ namespace blender::fn { /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_ShallowCopy +/** \name #GVArrayImpl * \{ */ -class GVArray_For_ShallowCopy : public GVArray { - private: - const GVArray &varray_; - - public: - GVArray_For_ShallowCopy(const GVArray &varray) - : GVArray(varray.type(), varray.size()), varray_(varray) - { - } - - private: - void get_impl(const int64_t index, void *r_value) const override - { - varray_.get(index, r_value); - } - - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override - { - varray_.get_to_uninitialized(index, r_value); - } - - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override - { - varray_.materialize_to_uninitialized(mask, dst); - } -}; -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #GVArray - * \{ */ - -void GVArray::materialize(void *dst) const -{ - this->materialize(IndexMask(size_), dst); -} - -void GVArray::materialize(const IndexMask mask, void *dst) const -{ - this->materialize_impl(mask, dst); -} - -void GVArray::materialize_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -72,18 +30,7 @@ void GVArray::materialize_impl(const IndexMask mask, void *dst) const } } -void GVArray::materialize_to_uninitialized(void *dst) const -{ - this->materialize_to_uninitialized(IndexMask(size_), dst); -} - -void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const -{ - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, dst); -} - -void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize_to_uninitialized(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -91,83 +38,75 @@ void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) } } -void GVArray::get_impl(const int64_t index, void *r_value) const +void GVArrayImpl::get(const int64_t index, void *r_value) const { type_->destruct(r_value); - this->get_to_uninitialized_impl(index, r_value); + this->get_to_uninitialized(index, r_value); } -bool GVArray::is_span_impl() const +bool GVArrayImpl::is_span() const { return false; } -GSpan GVArray::get_internal_span_impl() const +GSpan GVArrayImpl::get_internal_span() const { BLI_assert(false); return GSpan(*type_); } -bool GVArray::is_single_impl() const +bool GVArrayImpl::is_single() const { return false; } -void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const +void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const { BLI_assert(false); } -const void *GVArray::try_get_internal_varray_impl() const +bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const { - return nullptr; + return false; } -/** - * Creates a new `std::unique_ptr<GVArray>` based on this `GVArray`. - * The lifetime of the returned virtual array must not be longer than the lifetime of this virtual - * array. - */ -GVArrayPtr GVArray::shallow_copy() const +bool GVArrayImpl::may_have_ownership() const { - if (this->is_span()) { - return std::make_unique<GVArray_For_GSpan>(this->get_internal_span()); - } - if (this->is_single()) { - BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); - this->get_internal_single(buffer); - std::unique_ptr new_varray = std::make_unique<GVArray_For_SingleValue>(*type_, size_, buffer); - type_->destruct(buffer); - return new_varray; - } - return std::make_unique<GVArray_For_ShallowCopy>(*this); + /* Use true as default to avoid accidentally creating subclasses that have this set to false but + * actually own data. Subclasses should set the to false instead. */ + return true; } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray +/** \name #GVMutableArrayImpl * \{ */ -void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value) +GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size) +{ +} + +void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value) { BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); type_->copy_construct(value, buffer); - this->set_by_move_impl(index, buffer); + this->set_by_move(index, buffer); type_->destruct(buffer); } -void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value) { - this->set_by_move_impl(index, value); + this->set_by_move(index, value); type_->destruct(value); } -void GVMutableArray::set_all_impl(const void *src) +void GVMutableArrayImpl::set_all(const void *src) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->copy_assign_n(src, span.data(), size_); + const GSpan span = this->get_internal_span(); + type_->copy_assign_n(src, const_cast<void *>(span.data()), size_); } else { for (int64_t i : IndexRange(size_)) { @@ -176,149 +115,224 @@ void GVMutableArray::set_all_impl(const void *src) } } -void *GVMutableArray::try_get_internal_mutable_varray_impl() -{ - return nullptr; -} - void GVMutableArray::fill(const void *value) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->fill_assign_n(value, span.data(), size_); + const GSpan span = this->get_internal_span(); + this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size()); } else { - for (int64_t i : IndexRange(size_)) { + for (int64_t i : IndexRange(this->size())) { this->set_by_copy(i, value); } } } +bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const +{ + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_GSpan +/** \name #GVArrayImpl_For_GSpan * \{ */ -void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span) + : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) +{ +} + +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const +void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -bool GVArray_For_GSpan::is_span_impl() const +bool GVArrayImpl_For_GSpan::is_span() const { return true; } -GSpan GVArray_For_GSpan::get_internal_span_impl() const +GSpan GVArrayImpl_For_GSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +/** See #VArrayImpl_For_Span_final. */ +class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { + public: + using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray_For_GMutableSpan +/** \name #GVMutableArrayImpl_For_GMutableSpan * \{ */ -void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span) + : GVMutableArrayImpl(span.type(), span.size()), + data_(span.data()), + element_size_(span.type().size()) +{ +} + +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, + const int64_t size) + : GVMutableArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index, - void *r_value) const +void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index, + void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value) { type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value) { type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value) { type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -bool GVMutableArray_For_GMutableSpan::is_span_impl() const +bool GVMutableArrayImpl_For_GMutableSpan::is_span() const { return true; } -GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const +GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +class GVMutableArrayImpl_For_GMutableSpan_final final + : public GVMutableArrayImpl_For_GMutableSpan { + public: + using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValueRef +/** \name #GVArrayImpl_For_SingleValueRef * \{ */ -void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const -{ - type_->copy_assign(value_, r_value); -} +/* Generic virtual array where each element has the same value. The value is not owned. */ +class GVArrayImpl_For_SingleValueRef : public GVArrayImpl { + protected: + const void *value_ = nullptr; -void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index), - void *r_value) const -{ - type_->copy_construct(value_, r_value); -} + public: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl(type, size), value_(value) + { + } -bool GVArray_For_SingleValueRef::is_span_impl() const -{ - return size_ == 1; -} + protected: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size) + { + } -GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const -{ - return GSpan{*type_, value_, 1}; -} + void get(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_assign(value_, r_value); + } + void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_construct(value_, r_value); + } -bool GVArray_For_SingleValueRef::is_single_impl() const -{ - return true; -} + bool is_span() const override + { + return size_ == 1; + } + GSpan get_internal_span() const override + { + return GSpan{*type_, value_, 1}; + } -void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const -{ - type_->copy_assign(value_, r_value); -} + bool is_single() const override + { + return true; + } + void get_internal_single(void *r_value) const override + { + type_->copy_assign(value_, r_value); + } +}; + +class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef { + public: + using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef; + + private: + bool may_have_ownership() const override + { + return false; + } +}; /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValue +/** \name #GVArrayImpl_For_SingleValue * \{ */ -GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type, - const int64_t size, - const void *value) - : GVArray_For_SingleValueRef(type, size) -{ - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_construct(value, (void *)value_); -} +/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */ +class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef, + NonCopyable, + NonMovable { + public: + GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl_For_SingleValueRef(type, size) + { + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_construct(value, (void *)value_); + } -GVArray_For_SingleValue::~GVArray_For_SingleValue() -{ - type_->destruct((void *)value_); - MEM_freeN((void *)value_); -} + ~GVArrayImpl_For_SingleValue() override + { + type_->destruct((void *)value_); + MEM_freeN((void *)value_); + } +}; /** \} */ @@ -326,7 +340,7 @@ GVArray_For_SingleValue::~GVArray_For_SingleValue() /** \name #GVArray_GSpan * \{ */ -GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray) +GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -353,8 +367,8 @@ GVArray_GSpan::~GVArray_GSpan() /** \name #GVMutableArray_GSpan * \{ */ -GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span) - : GMutableSpan(varray.type()), varray_(varray) +GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span) + : GMutableSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -405,48 +419,314 @@ void GVMutableArray_GSpan::disable_not_applied_warning() /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SlicedGVArray +/** \name #GVArrayImpl_For_SlicedGVArray * \{ */ -void GVArray_For_SlicedGVArray::get_impl(const int64_t index, void *r_value) const +class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl { + protected: + GVArray varray_; + int64_t offset_; + + public: + GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice) + : GVArrayImpl(varray.type(), slice.size()), + varray_(std::move(varray)), + offset_(slice.start()) + { + BLI_assert(slice.one_after_last() <= varray_.size()); + } + + void get(const int64_t index, void *r_value) const override + { + varray_.get(index + offset_, r_value); + } + + void get_to_uninitialized(const int64_t index, void *r_value) const override + { + varray_.get_to_uninitialized(index + offset_, r_value); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayCommon + * \{ */ + +GVArrayCommon::GVArrayCommon() = default; + +GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_) +{ + impl_ = this->impl_from_storage(); +} + +GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) +{ + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +GVArrayCommon::GVArrayCommon(const GVArrayImpl *impl) : impl_(impl) +{ + storage_ = impl_; +} + +GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get()) +{ + if (impl) { + storage_ = std::move(impl); + } +} + +GVArrayCommon::~GVArrayCommon() = default; + +void GVArrayCommon::materialize(void *dst) const +{ + this->materialize(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize(const IndexMask mask, void *dst) const +{ + impl_->materialize(mask, dst); +} + +void GVArrayCommon::materialize_to_uninitialized(void *dst) const +{ + this->materialize_to_uninitialized(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize_to_uninitialized(const IndexMask mask, void *dst) const +{ + BLI_assert(mask.min_array_size() <= impl_->size()); + impl_->materialize_to_uninitialized(mask, dst); +} + +bool GVArrayCommon::may_have_ownership() const +{ + return impl_->may_have_ownership(); +} + +void GVArrayCommon::copy_from(const GVArrayCommon &other) +{ + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); +} + +void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept +{ + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +/* Returns true when the virtual array is stored as a span internally. */ +bool GVArrayCommon::is_span() const +{ + if (this->is_empty()) { + return true; + } + return impl_->is_span(); +} + +/* Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. */ +GSpan GVArrayCommon::get_internal_span() const { - varray_.get(index + offset_, r_value); + BLI_assert(this->is_span()); + if (this->is_empty()) { + return GSpan(impl_->type()); + } + return impl_->get_internal_span(); } -void GVArray_For_SlicedGVArray::get_to_uninitialized_impl(const int64_t index, void *r_value) const +/* Returns true when the virtual array returns the same value for every index. */ +bool GVArrayCommon::is_single() const { - varray_.get_to_uninitialized(index + offset_, r_value); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); +} + +/* Copies the value that is used for every element into `r_value`, which is expected to point to + * initialized memory. This invokes undefined behavior if the virtual array would not return the + * same value for every index. */ +void GVArrayCommon::get_internal_single(void *r_value) const +{ + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + impl_->get(0, r_value); + return; + } + impl_->get_internal_single(r_value); +} + +/* Same as `get_internal_single`, but `r_value` points to initialized memory. */ +void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const +{ + impl_->type().default_construct(r_value); + this->get_internal_single(r_value); +} + +const GVArrayImpl *GVArrayCommon::impl_from_storage() const +{ + return storage_.extra_info().get_varray(storage_.get()); +} + +IndexRange GVArrayCommon::index_range() const +{ + return IndexRange(this->size()); } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_Slice +/** \name #GVArray * \{ */ -GVArray_Slice::GVArray_Slice(const GVArray &varray, const IndexRange slice) +GVArray::GVArray(const GVArray &other) = default; + +GVArray::GVArray(GVArray &&other) noexcept = default; + +GVArray::GVArray(const GVArrayImpl *impl) : GVArrayCommon(impl) { - if (varray.is_span()) { - /* Create a new virtual for the sliced span. */ - const GSpan span = varray.get_internal_span(); - const GSpan sliced_span = span.slice(slice.start(), slice.size()); - varray_span_.emplace(sliced_span); - varray_ = &*varray_span_; - } - else if (varray.is_single()) { - /* Can just use the existing virtual array, because it's the same value for the indices in the - * slice anyway. */ - varray_ = &varray; - } - else { - /* Generic version when none of the above method works. - * We don't necessarily want to materialize the input varray because there might be - * large distances between the required indices. Then we would materialize many elements that - * are not accessed later on. - */ - varray_any_.emplace(varray, slice); - varray_ = &*varray_any_; +} + +GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl)) +{ +} + +GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value); +} + +GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value); +} + +GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size) +{ + return GVArray::ForSingleRef(type, size, type.default_value()); +} + +GVArray GVArray::ForSpan(GSpan span) +{ + return GVArray::For<GVArrayImpl_For_GSpan_final>(span); +} + +class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan { + protected: + GArray<> array_; + + public: + GVArrayImpl_For_GArray(GArray<> array) + : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array)) + { } +}; + +GVArray GVArray::ForGArray(GArray<> array) +{ + return GVArray::For<GVArrayImpl_For_GArray>(array); +} + +GVArray GVArray::ForEmpty(const CPPType &type) +{ + return GVArray::ForSpan(GSpan(type)); +} + +GVArray GVArray::slice(IndexRange slice) const +{ + return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice); +} + +GVArray &GVArray::operator=(const GVArray &other) +{ + this->copy_from(other); + return *this; +} + +GVArray &GVArray::operator=(GVArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVMutableArray + * \{ */ + +GVMutableArray::GVMutableArray(const GVMutableArray &other) = default; +GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default; + +GVMutableArray::GVMutableArray(GVMutableArrayImpl *impl) : GVArrayCommon(impl) +{ +} + +GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl) + : GVArrayCommon(std::move(impl)) +{ +} + +GVMutableArray GVMutableArray::ForSpan(GMutableSpan span) +{ + return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span); +} + +GVMutableArray::operator GVArray() const & +{ + GVArray varray; + varray.copy_from(*this); + return varray; +} + +GVMutableArray::operator GVArray() &&noexcept +{ + GVArray varray; + varray.move_from(std::move(*this)); + return varray; +} + +GVMutableArray &GVMutableArray::operator=(const GVMutableArray &other) +{ + this->copy_from(other); + return *this; +} + +GVMutableArray &GVMutableArray::operator=(GVMutableArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +GVMutableArrayImpl *GVMutableArray::get_implementation() const +{ + return this->get_impl(); +} + +/* Copy the values from the source buffer to all elements in the virtual array. */ +void GVMutableArray::set_all(const void *src) +{ + this->get_impl()->set_all(src); +} + +GMutableSpan GVMutableArray::get_internal_span() const +{ + BLI_assert(this->is_span()); + const GSpan span = impl_->get_internal_span(); + return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); } /** \} */ diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc index 6b90ce993ae..e3c0d3109fa 100644 --- a/source/blender/functions/intern/generic_virtual_vector_array.cc +++ b/source/blender/functions/intern/generic_virtual_vector_array.cc @@ -18,13 +18,13 @@ namespace blender::fn { -void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const +void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const { vector_array_.get_vector_element(index_, index_in_vector, r_value); } -void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector, - void *r_value) const +void GVArray_For_GVVectorArrayIndex::get_to_uninitialized(const int64_t index_in_vector, + void *r_value) const { type_->default_construct(r_value); vector_array_.get_vector_element(index_, index_in_vector, r_value); @@ -32,14 +32,14 @@ void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t ind int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const { - return array_.size(); + return varray_.size(); } void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index), const int64_t index_in_vector, void *r_value) const { - array_.get(index_in_vector, r_value); + varray_.get(index_in_vector, r_value); } bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc index bb657f321ec..ee2c69068db 100644 --- a/source/blender/functions/intern/multi_function.cc +++ b/source/blender/functions/intern/multi_function.cc @@ -18,28 +18,9 @@ namespace blender::fn { -class DummyMultiFunction : public MultiFunction { - public: - DummyMultiFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Dummy"}; - return signature.build(); - } - - void call(IndexMask UNUSED(mask), - MFParams UNUSED(params), - MFContext UNUSED(context)) const override - { - } -}; - -static DummyMultiFunction dummy_multi_function_; -const MultiFunction &dummy_multi_function = dummy_multi_function_; +std::string MultiFunction::debug_name() const +{ + return signature_ref_->function_name; +} } // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc index f891f162820..24f9bbe0179 100644 --- a/source/blender/functions/intern/multi_function_builder.cc +++ b/source/blender/functions/intern/multi_function_builder.cc @@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type, } value_ = value; - MFSignatureBuilder signature{"Constant " + type.name()}; - std::stringstream ss; - type.print_or_default(value, ss, type.name()); - signature.single_output(ss.str(), type); + MFSignatureBuilder signature{"Constant"}; + signature.single_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const return type_.is_equal(value_, _other->value_); } -static std::string gspan_to_string(GSpan array) -{ - const CPPType &type = array.type(); - std::stringstream ss; - ss << "["; - const int64_t max_amount = 5; - for (int64_t i : IndexRange(std::min(max_amount, array.size()))) { - type.print_or_default(array[i], ss, type.name()); - ss << ", "; - } - if (max_amount < array.size()) { - ss << "..."; - } - ss << "]"; - return ss.str(); -} - CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array) { const CPPType &type = array.type(); - MFSignatureBuilder signature{"Constant " + type.name() + " Vector"}; - signature.vector_output(gspan_to_string(array), type); + MFSignatureBuilder signature{"Constant Vector"}; + signature.vector_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask, } } -CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, +CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types) : output_amount_(output_types.size()) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Default Output"}; for (MFDataType data_type : input_types) { signature.input("Input", data_type); } @@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU } } -CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type) +CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Copy"}; signature.input("Input", data_type); signature.output("Output", data_type); signature_ = signature.build(); diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc index 5a8c621f0b3..eefe647644d 100644 --- a/source/blender/functions/intern/multi_function_parallel.cc +++ b/source/blender/functions/intern/multi_function_parallel.cc @@ -54,7 +54,6 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext const IndexRange input_slice_range{input_slice_start, input_slice_size}; MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()}; - ResourceScope &scope = sub_params.resource_scope(); /* All parameters are sliced so that the wrapped multi-function does not have to take care of * the index offset. */ @@ -63,8 +62,7 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext switch (param_type.category()) { case MFParamType::SingleInput: { const GVArray &varray = params.readonly_single_input(param_index); - const GVArray &sliced_varray = scope.construct<GVArray_Slice>(varray, input_slice_range); - sub_params.add_readonly_single_input(sliced_varray); + sub_params.add_readonly_single_input(varray.slice(input_slice_range)); break; } case MFParamType::SingleMutable: { diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc index 986c5dff0c4..804beb7d66f 100644 --- a/source/blender/functions/intern/multi_function_procedure.cc +++ b/source/blender/functions/intern/multi_function_procedure.cc @@ -782,7 +782,7 @@ class MFProcedureDotExport { void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss) { const MultiFunction &fn = instruction.fn(); - this->instruction_name_format(fn.name() + ": ", ss); + this->instruction_name_format(fn.debug_name() + ": ", ss); for (const int param_index : fn.param_indices()) { const MFParamType param_type = fn.param_type(param_index); const MFVariable *variable = instruction.params()[param_index]; diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc index 6d2d121bafd..06c97fd1173 100644 --- a/source/blender/functions/intern/multi_function_procedure_executor.cc +++ b/source/blender/functions/intern/multi_function_procedure_executor.cc @@ -20,13 +20,12 @@ namespace blender::fn { -MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure) - : procedure_(procedure) +MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure) { - MFSignatureBuilder signature(std::move(name)); + MFSignatureBuilder signature("Procedure Executor"); for (const ConstMFParameter ¶m : procedure.params()) { - signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type())); + signature.add("Parameter", MFParamType(param.type, param.variable->data_type())); } signature_ = signature.build(); @@ -66,6 +65,7 @@ struct VariableValue_GVArray : public VariableValue { VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data) { + BLI_assert(data); } }; @@ -756,7 +756,7 @@ class VariableState : NonCopyable, NonMovable { switch (value_->type) { case ValueType::GVArray: { - const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data}; + const VArray<bool> varray = this->value_as<VariableValue_GVArray>()->data.typed<bool>(); for (const int i : mask) { r_indices[varray[i]].append(i); } diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc index 041cdbd0f00..4614f9eee58 100644 --- a/source/blender/functions/tests/FN_field_test.cc +++ b/source/blender/functions/tests/FN_field_test.cc @@ -34,14 +34,12 @@ class IndexFieldInput final : public FieldInput { { } - const GVArray *get_varray_for_context(const FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { auto index_func = [](int i) { return i; }; - return &scope.construct< - GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } }; @@ -162,9 +160,9 @@ class TwoOutputFunction : public MultiFunction { MFSignature signature_; public: - TwoOutputFunction(StringRef name) + TwoOutputFunction() { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Two Outputs"}; signature.single_input<int>("In1"); signature.single_input<int>("In2"); signature.single_output<int>("Add"); @@ -192,8 +190,8 @@ TEST(field, FunctionTwoOutputs) GField index_field_1{std::make_shared<IndexFieldInput>()}; GField index_field_2{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2})); GField result_field_1{fn, 0}; GField result_field_2{fn, 1}; @@ -223,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs) { GField index_field{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field})); Array<int64_t> mask_indices = {2, 4, 6, 8}; IndexMask mask = mask_indices.as_span(); @@ -240,20 +238,20 @@ TEST(field, TwoFunctionsTwoOutputs) FieldContext field_context; FieldEvaluator field_evaluator{field_context, &mask}; - const VArray<int> *result_1 = nullptr; - const VArray<int> *result_2 = nullptr; + VArray<int> result_1; + VArray<int> result_2; field_evaluator.add(result_field_1, &result_1); field_evaluator.add(result_field_2, &result_2); field_evaluator.evaluate(); - EXPECT_EQ(result_1->get(2), 4); - EXPECT_EQ(result_1->get(4), 8); - EXPECT_EQ(result_1->get(6), 12); - EXPECT_EQ(result_1->get(8), 16); - EXPECT_EQ(result_2->get(2), 24); - EXPECT_EQ(result_2->get(4), 28); - EXPECT_EQ(result_2->get(6), 32); - EXPECT_EQ(result_2->get(8), 36); + EXPECT_EQ(result_1.get(2), 4); + EXPECT_EQ(result_1.get(4), 8); + EXPECT_EQ(result_1.get(6), 12); + EXPECT_EQ(result_1.get(8), 16); + EXPECT_EQ(result_2.get(2), 24); + EXPECT_EQ(result_2.get(4), 28); + EXPECT_EQ(result_2.get(6), 32); + EXPECT_EQ(result_2.get(8), 36); } TEST(field, SameFieldTwice) @@ -264,16 +262,16 @@ TEST(field, SameFieldTwice) FieldContext field_context; IndexMask mask{IndexRange(2)}; ResourceScope scope; - Vector<const GVArray *> results = evaluate_fields( + Vector<GVArray> results = evaluate_fields( scope, {constant_field, constant_field}, mask, field_context); - GVArray_Typed<int> varray1{*results[0]}; - GVArray_Typed<int> varray2{*results[1]}; + VArray<int> varray1 = results[0].typed<int>(); + VArray<int> varray2 = results[1].typed<int>(); - EXPECT_EQ(varray1->get(0), 10); - EXPECT_EQ(varray1->get(1), 10); - EXPECT_EQ(varray2->get(0), 10); - EXPECT_EQ(varray2->get(1), 10); + EXPECT_EQ(varray1.get(0), 10); + EXPECT_EQ(varray1.get(1), 10); + EXPECT_EQ(varray2.get(0), 10); + EXPECT_EQ(varray2.get(1), 10); } TEST(field, IgnoredOutput) @@ -283,12 +281,12 @@ TEST(field, IgnoredOutput) FieldContext field_context; FieldEvaluator field_evaluator{field_context, 10}; - const VArray<int> *results = nullptr; + VArray<int> results; field_evaluator.add(field, &results); field_evaluator.evaluate(); - EXPECT_EQ(results->get(0), 5); - EXPECT_EQ(results->get(3), 5); + EXPECT_EQ(results.get(0), 5); + EXPECT_EQ(results.get(3), 5); } } // namespace blender::fn::tests diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc index 0b4b88fba3d..e3de23550c5 100644 --- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc +++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc @@ -9,6 +9,43 @@ namespace blender::fn::tests { +TEST(multi_function_procedure, ConstantOutput) +{ + /** + * procedure(int *var2) { + * var1 = 5; + * var2 = var1 + var1; + * } + */ + + CustomMF_Constant<int> constant_fn{5}; + CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }}; + + MFProcedure procedure; + MFProcedureBuilder builder{procedure}; + + auto [var1] = builder.add_call<1>(constant_fn); + auto [var2] = builder.add_call<1>(add_fn, {var1, var1}); + builder.add_destruct(*var1); + builder.add_return(); + builder.add_output_parameter(*var2); + + EXPECT_TRUE(procedure.validate()); + + MFProcedureExecutor executor{procedure}; + + MFParamsBuilder params{executor, 2}; + MFContextBuilder context; + + Array<int> output_array(2); + params.add_uninitialized_single_output(output_array.as_mutable_span()); + + executor.call(IndexRange(2), params, context); + + EXPECT_EQ(output_array[0], 10); + EXPECT_EQ(output_array[1], 10); +} + TEST(multi_function_procedure, SimpleTest) { /** @@ -36,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor executor{"My Procedure", procedure}; + MFProcedureExecutor executor{procedure}; MFParamsBuilder params{executor, 3}; MFContextBuilder context; @@ -88,7 +125,7 @@ TEST(multi_function_procedure, BranchTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Condition Test", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params(procedure_fn, 5); Array<int> values_a = {1, 5, 3, 6, 2}; @@ -130,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne) builder.add_return(); builder.add_output_parameter(*var2); - MFProcedureExecutor procedure_fn{"Evaluate One", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> values_out = {1, 2, 3, 4, 5}; @@ -202,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Simple Loop", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> counts = {4, 3, 7, 6, 4}; @@ -258,7 +295,7 @@ TEST(multi_function_procedure, Vectors) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Vectors", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> v1 = {5, 2, 3}; @@ -322,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure}; + MFProcedureExecutor procedure_fn{procedure}; Array<int> inputs = {4, 1, 6, 2, 3}; Array<int> results(5, -1); diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc index d99993b35ac..20ca00cf598 100644 --- a/source/blender/functions/tests/FN_multi_function_test.cc +++ b/source/blender/functions/tests/FN_multi_function_test.cc @@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant) { int value = 42; CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false}; - EXPECT_EQ(fn.param_name(0), "42"); Array<int> outputs(4, 0); @@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray) { std::array<int, 4> values = {3, 4, 5, 6}; CustomMF_GenericConstantArray fn{GSpan(Span(values))}; - EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]"); GVectorArray vector_array{CPPType::get<int32_t>(), 4}; GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array}; diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 24f0b6308ba..7aaaec9f0c5 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -50,23 +50,23 @@ static void copy_attributes_to_points(CurveEval &curve, /* Copy builtin control point attributes. */ if (source_attribute_ids.contains("tilt")) { - const fn::GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( "tilt", ATTR_DOMAIN_POINT, 0.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); + tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); } }); source_attribute_ids.remove_contained("tilt"); } if (source_attribute_ids.contains("radius")) { - const fn::GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>( "radius", ATTR_DOMAIN_POINT, 1.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *radius_attribute, point_to_vert_maps[i], splines[i]->radii()); + radius_attribute, point_to_vert_maps[i], splines[i]->radii()); } }); source_attribute_ids.remove_contained("radius"); @@ -82,7 +82,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const fn::GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read( + const fn::GVArray mesh_attribute = mesh_component.attribute_try_get_for_read( attribute_id, ATTR_DOMAIN_POINT); /* Some attributes might not exist if they were builtin attribute on domains that don't * have any elements, i.e. a face attribute on the output of the line primitive node. */ @@ -90,7 +90,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type()); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { @@ -101,10 +101,10 @@ static void copy_attributes_to_points(CurveEval &curve, BLI_assert(spline_attribute); /* Copy attribute based on the map for this spline. */ - attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) { + attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); copy_attribute_to_points<T>( - mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); + mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); }); } }); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 88d717eb032..3773af70498 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -579,9 +579,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] c2 = ratiod(v0[1], v1[1], v[1]); return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM); } - else { - return false; - } + return false; } if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) { @@ -592,9 +590,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] c1 = ratiod(v0[0], v1[0], v[0]); return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM); } - else { - return false; - } + return false; } if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index b92b341fb73..4868096e594 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../windowmanager ../editors/include diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 0d3d39839b2..047c3d3da00 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -92,6 +92,7 @@ void imm_draw_cylinder_wire_3d( void imm_draw_cylinder_fill_3d( uint pos, float base, float top, float height, int slices, int stacks); +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos); #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 032974db8d1..df18b89bd67 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -602,3 +602,55 @@ void imm_draw_cylinder_fill_3d( } immEnd(); } + +/* Circle Drawing - Tables for Optimized Drawing Speed */ +#define CIRCLE_RESOL 32 + +static void circball_array_fill(const float verts[CIRCLE_RESOL][3], + const float cent[3], + float rad, + const float tmat[4][4]) +{ + /* 32 values of sin function (still same result!) */ + const float sinval[CIRCLE_RESOL] = { + 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, + 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, + 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, + -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, + -0.57126821, -0.39435585, -0.20129852, 0.00000000, + }; + + /* 32 values of cos function (still same result!) */ + const float cosval[CIRCLE_RESOL] = { + 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, + 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, + -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, + -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, + 0.82076344, 0.91895781, 0.97952994, 1.00000000, + }; + + float vx[3], vy[3]; + float *viter = (float *)verts; + + mul_v3_v3fl(vx, tmat[0], rad); + mul_v3_v3fl(vy, tmat[1], rad); + + for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { + viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; + viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; + viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; + } +} + +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) +{ + float verts[CIRCLE_RESOL][3]; + + circball_array_fill(verts, cent, rad, tmat); + + immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; i++) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index ac42c5875c8..7fd473069c2 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -18,6 +18,7 @@ void GPUTest::SetUp() CLG_init(); ghost_system = GHOST_CreateSystem(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); + GHOST_ActivateOpenGLContext(ghost_context); context = GPU_context_create(nullptr); GPU_init(); } diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 87f2fd124c0..1d81653c7cd 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -58,6 +58,8 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "DNA_scene_types.h" + #include "MEM_guardedalloc.h" #ifdef WITH_AVI @@ -1443,7 +1445,15 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ * * The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker * and is fixed in the newer versions than 4.3.1. */ - anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0); + + const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt); + + int planes = R_IMF_PLANES_RGBA; + if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) { + planes = R_IMF_PLANES_RGB; + } + + anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, planes, 0); anim->cur_frame_final->rect = MEM_mallocN_aligned( (size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf"); anim->cur_frame_final->mall |= IB_rect; diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index bbb0f3b5b22..6cd87e29c9d 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -183,13 +183,13 @@ struct anim_index *IMB_indexer_open(const char *name) header[12] = 0; if (memcmp(header, binary_header_str, 8) != 0) { - fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name); + fprintf(stderr, "Error reading %s: Binary file type string mismatch\n", name); fclose(fp); return NULL; } if (atoi(header + 9) != INDEX_FILE_VERSION) { - fprintf(stderr, "Error reading %s: File version missmatch\n", name); + fprintf(stderr, "Error reading %s: File version mismatch\n", name); fclose(fp); return NULL; } @@ -222,7 +222,7 @@ struct anim_index *IMB_indexer_open(const char *name) } if (UNLIKELY(items_read != idx->num_entries * 5)) { - fprintf(stderr, "Error: Element data size missmatch in: %s\n", name); + fprintf(stderr, "Error: Element data size mismatch in: %s\n", name); MEM_freeN(idx->entries); MEM_freeN(idx); fclose(fp); diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 4f316150e10..773a3486233 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -122,7 +122,12 @@ static void moviecache_valfree(void *val) PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf); - MEM_CacheLimiter_unmanage(item->c_handle); + if (item->c_handle) { + BLI_mutex_lock(&limitor_lock); + MEM_CacheLimiter_unmanage(item->c_handle); + BLI_mutex_unlock(&limitor_lock); + } + if (item->ibuf) { IMB_freeImBuf(item->ibuf); } @@ -263,6 +268,7 @@ void IMB_moviecache_destruct(void) { if (limitor) { delete_MEM_CacheLimiter(limitor); + limitor = NULL; } } diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 8f410978211..7275d0addf0 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -166,9 +166,10 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) const int quad_method = args_.export_params->quad_method; const int ngon_method = args_.export_params->ngon_method; - struct BMeshCreateParams bmcp = {false}; - struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); + BMeshCreateParams bmesh_create_params{}; + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = true; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); @@ -189,6 +190,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) m_custom_data_config.totpoly = mesh->totpoly; m_custom_data_config.totloop = mesh->totloop; m_custom_data_config.totvert = mesh->totvert; + m_custom_data_config.timesample_index = timesample_index_; try { if (is_subd_) { @@ -350,7 +352,7 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - if (frame_has_been_written_ || !args_.export_params->vcolors) { + if (!args_.export_params->vcolors) { return; } diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 087d60f8896..188e8daac8f 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -176,29 +176,23 @@ static void write_uv(const OCompoundProperty &prop, UInt32ArraySample(&indices.front(), indices.size()), kFacevaryingScope); param.set(sample); + param.setTimeSampling(config.timesample_index); config.abc_uv_maps[uv_map_name] = param; } -/* Convention to write Vertex Colors: - * - C3fGeomParam/C4fGeomParam on the arbGeomParam - * - set scope as vertex varying - */ -static void write_mcol(const OCompoundProperty &prop, - const CDStreamConfig &config, - void *data, - const char *name) +static void get_cols(const CDStreamConfig &config, + std::vector<Imath::C4f> &buffer, + std::vector<uint32_t> &uvidx, + void *cd_data) { const float cscale = 1.0f / 255.0f; MPoly *polys = config.mpoly; MLoop *mloops = config.mloop; - MCol *cfaces = static_cast<MCol *>(data); - - std::vector<Imath::C4f> buffer; - std::vector<uint32_t> indices; + MCol *cfaces = static_cast<MCol *>(cd_data); buffer.reserve(config.totvert); - indices.reserve(config.totvert); + uvidx.reserve(config.totvert); Imath::C4f col; @@ -217,17 +211,44 @@ static void write_mcol(const OCompoundProperty &prop, col[3] = cface->b * cscale; buffer.push_back(col); - indices.push_back(buffer.size() - 1); + uvidx.push_back(buffer.size() - 1); } } +} + +/* Convention to write Vertex Colors: + * - C3fGeomParam/C4fGeomParam on the arbGeomParam + * - set scope as vertex varying + */ +static void write_mcol(const OCompoundProperty &prop, + CDStreamConfig &config, + void *data, + const char *name) +{ + std::vector<uint32_t> indices; + std::vector<Imath::C4f> buffer; + + get_cols(config, buffer, indices, data); + + if (indices.empty() || buffer.empty()) { + return; + } - OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); + std::string vcol_name(name); + OC4fGeomParam param = config.abc_vertex_colors[vcol_name]; + + if (!param.valid()) { + param = OC4fGeomParam(prop, name, true, kFacevaryingScope, 1); + } OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()), UInt32ArraySample(&indices.front(), indices.size()), kVertexScope); param.set(sample); + param.setTimeSampling(config.timesample_index); + + config.abc_vertex_colors[vcol_name] = param; } void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config) diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 03e6f697f0c..5eae6307474 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -66,6 +66,7 @@ struct CDStreamConfig { float weight; float time; + int timesample_index; bool use_vertex_interpolation; Alembic::AbcGeom::index_t index; Alembic::AbcGeom::index_t ceil_index; @@ -82,6 +83,9 @@ struct CDStreamConfig { /* ORCO coordinates, aka Generated Coordinates. */ Alembic::AbcGeom::OV3fGeomParam abc_orco; + /* Mapping from vertex color layer name to its Alembic color data. */ + std::map<std::string, Alembic::AbcGeom::OC4fGeomParam> abc_vertex_colors; + CDStreamConfig() : mloop(NULL), totloop(0), diff --git a/source/blender/io/avi/intern/avi.c b/source/blender/io/avi/intern/avi.c index 87058693378..221e56ac793 100644 --- a/source/blender/io/avi/intern/avi.c +++ b/source/blender/io/avi/intern/avi.c @@ -591,7 +591,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) BLI_fseek(movie->fp, size - 4, SEEK_CUR); if (GET_FCC(movie->fp) != FCC("idx1")) { - DEBUG_PRINT("bad index informatio\n"); + DEBUG_PRINT("bad index information\n"); return AVI_ERROR_FORMAT; } diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp index 9ba59c0414d..56274e7e6ca 100644 --- a/source/blender/io/collada/AnimationExporter.cpp +++ b/source/blender/io/collada/AnimationExporter.cpp @@ -549,7 +549,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa param.push_back("TRANSFORM"); } else { - /* assumes if axis isn't specified all axises are added */ + /* assumes if axis isn't specified all axes are added */ param.push_back("X"); param.push_back("Y"); param.push_back("Z"); diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 60c4a9bad13..c1f25ea9a26 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -444,14 +444,14 @@ void bc_triangulate_mesh(Mesh *me) /* XXX: The triangulation method selection could be offered in the UI. */ int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; - const struct BMeshCreateParams bm_create_params = {0}; + const BMeshCreateParams bm_create_params{}; BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params); - BMeshFromMeshParams bm_from_me_params = {0}; + BMeshFromMeshParams bm_from_me_params{}; bm_from_me_params.calc_face_normal = true; BM_mesh_bm_from_me(bm, me, &bm_from_me_params); BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr); - BMeshToMeshParams bm_to_me_params = {0}; + BMeshToMeshParams bm_to_me_params{}; bm_to_me_params.calc_object_remap = false; BM_mesh_bm_to_me(nullptr, bm, me, &bm_to_me_params); BM_mesh_free(bm); diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h index fab867b38b3..cb004910c1e 100644 --- a/source/blender/io/gpencil/gpencil_io.h +++ b/source/blender/io/gpencil/gpencil_io.h @@ -82,6 +82,7 @@ typedef enum eGpencilExportSelect { typedef enum eGpencilExportFrame { GP_EXPORT_FRAME_ACTIVE = 0, GP_EXPORT_FRAME_SELECTED = 1, + GP_EXPORT_FRAME_SCENE = 2, } eGpencilExportFrame; bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams); diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc index 544c51e0b4f..95f5839682f 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc @@ -112,32 +112,39 @@ static bool gpencil_io_export_pdf(Depsgraph *depsgraph, exporter->frame_number_set(iparams->frame_cur); result |= exporter->new_document(); - const bool use_frame_selected = (iparams->frame_mode == GP_EXPORT_FRAME_SELECTED); - if (use_frame_selected) { - for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) { - if (!is_keyframe_included(gpd_eval, i, use_frame_selected)) { - continue; - } - - CFRA = i; - BKE_scene_graph_update_for_newframe(depsgraph); + switch (iparams->frame_mode) { + case GP_EXPORT_FRAME_ACTIVE: { exporter->prepare_camera_params(scene, iparams); - exporter->frame_number_set(i); exporter->add_newpage(); exporter->add_body(); + result = exporter->write(); + break; } - result = exporter->write(); - /* Back to original frame. */ - exporter->frame_number_set(iparams->frame_cur); - CFRA = iparams->frame_cur; - BKE_scene_camera_switch_update(scene); - BKE_scene_graph_update_for_newframe(depsgraph); - } - else { - exporter->prepare_camera_params(scene, iparams); - exporter->add_newpage(); - exporter->add_body(); - result = exporter->write(); + case GP_EXPORT_FRAME_SELECTED: + case GP_EXPORT_FRAME_SCENE: { + for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) { + if ((iparams->frame_mode == GP_EXPORT_FRAME_SELECTED) && + (!is_keyframe_included(gpd_eval, i, true))) { + continue; + } + + CFRA = i; + BKE_scene_graph_update_for_newframe(depsgraph); + exporter->prepare_camera_params(scene, iparams); + exporter->frame_number_set(i); + exporter->add_newpage(); + exporter->add_body(); + } + result = exporter->write(); + /* Back to original frame. */ + exporter->frame_number_set(iparams->frame_cur); + CFRA = iparams->frame_cur; + BKE_scene_camera_switch_update(scene); + BKE_scene_graph_update_for_newframe(depsgraph); + break; + } + default: + break; } return result; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6dc2d00252f..d587bd8082b 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -728,7 +728,7 @@ typedef enum eBConstraint_Flags { /* bConstraint->ownspace/tarspace */ typedef enum eBConstraint_SpaceTypes { - /** Default for all - worldspace. */ + /** Default for all - world-space. */ CONSTRAINT_SPACE_WORLD = 0, /** For all - custom space. */ CONSTRAINT_SPACE_CUSTOM = 5, diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 0cbef540306..d8065410f2b 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -513,7 +513,7 @@ typedef struct FluidDomainSettings { float p1[3]; /* End point of BB in local space. */ float dp0[3]; /* Difference from object center to grid start point. */ float cell_size[3]; /* Size of simulation cell in local space. */ - float global_size[3]; /* Global size of domain axises. */ + float global_size[3]; /* Global size of domain axes. */ float prev_loc[3]; int shift[3]; /* Current domain shift in simulation cells. */ float shift_f[3]; /* Exact domain shift. */ @@ -694,7 +694,7 @@ typedef struct FluidDomainSettings { char openvdb_data_depth; char _pad11[7]; /* Unused. */ - /* -- Deprecated / unsed options (below). -- */ + /* -- Deprecated / unused options (below). -- */ /* View options. */ int viewsettings; diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 2464eb05a6d..64c8fd3e3a9 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -142,6 +142,12 @@ typedef enum eImageTextureResolution { IMA_TEXTURE_RESOLUTION_LEN } eImageTextureResolution; +typedef struct Image_Runtime { + /* Mutex used to guarantee thread-safe access to the cached ImBuf of the corresponding image ID. + */ + void *cache_mutex; +} Image_Runtime; + typedef struct Image { ID id; @@ -208,6 +214,8 @@ typedef struct Image { /** ImageView. */ ListBase views; struct Stereo3dFormat *stereo3d_format; + + Image_Runtime runtime; } Image; /* **************** IMAGE ********************* */ diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 038de8e49cc..1a3bda34a84 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -149,7 +149,7 @@ BLI_STATIC_ASSERT_ALIGN(LightGridCache, 16) typedef struct LightCacheTexture { struct GPUTexture *tex; - /** Copy of GPU datas to create GPUTextures on file read. */ + /** Copy of GPU data to create GPUTextures on file read. */ char *data; int tex_size[3]; char data_type; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d5d2520ddf6..59cf4da26f6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -46,6 +46,7 @@ struct bNodePreview; struct bNodeTreeExec; struct bNodeType; struct uiBlock; +struct PreviewImage; #define NODE_MAXSTR 64 @@ -80,6 +81,19 @@ typedef struct bNodeStack { #define NS_CR_FIT 4 #define NS_CR_STRETCH 5 +/** Workaround to forward-declare C++ type in C header. */ +#ifdef __cplusplus +namespace blender::nodes { +class NodeDeclaration; +class SocketDeclaration; +} // namespace blender::nodes +using NodeDeclarationHandle = blender::nodes::NodeDeclaration; +using SocketDeclarationHandle = blender::nodes::SocketDeclaration; +#else +typedef struct NodeDeclarationHandle NodeDeclarationHandle; +typedef struct SocketDeclarationHandle SocketDeclarationHandle; +#endif + typedef struct bNodeSocket { struct bNodeSocket *next, *prev, *new_sock; @@ -152,6 +166,12 @@ typedef struct bNodeSocket { * kept for forward compatibility */ /** Custom data for inputs, only UI writes in this. */ bNodeStack ns DNA_DEPRECATED; + + /** + * References a socket declaration that is owned by `node->declaration`. This is only runtime + * data. It has to be updated when the node declaration changes. + */ + const SocketDeclarationHandle *declaration; } bNodeSocket; /* sock->type */ @@ -219,16 +239,6 @@ typedef enum eNodeSocketFlag { SOCK_HIDE_LABEL = (1 << 12), } eNodeSocketFlag; -/** Workaround to forward-declare C++ type in C header. */ -#ifdef __cplusplus -namespace blender::nodes { -class NodeDeclaration; -} -using NodeDeclarationHandle = blender::nodes::NodeDeclaration; -#else -typedef struct NodeDeclarationHandle NodeDeclarationHandle; -#endif - /* TODO: Limit data in bNode to what we want to see saved. */ typedef struct bNode { struct bNode *next, *prev, *new_node; @@ -292,7 +302,7 @@ typedef struct bNode { char _pad1[4]; - /** Entire boundbox (worldspace). */ + /** Entire boundbox (world-space). */ rctf totr; /** Optional buttons area. */ rctf butr; @@ -561,10 +571,15 @@ typedef struct bNodeTree { int (*test_break)(void *); void (*update_draw)(void *); void *tbh, *prh, *sdh, *udh; + + /** Image representing what the node group does. */ + struct PreviewImage *preview; } bNodeTree; /* ntree->type, index */ -#define NTREE_CUSTOM -1 /* for dynamically registered custom types */ + +#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */ +#define NTREE_CUSTOM -1 /* for dynamically registered custom types */ #define NTREE_SHADER 0 #define NTREE_COMPOSIT 1 #define NTREE_TEXTURE 2 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e94541fdc7f..57c8ef200ae 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -311,7 +311,7 @@ typedef struct Object { float rotAxis[3], drotAxis[3]; /** Axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** Final worldspace matrix with constraints & animsys applied. */ + /** Final world-space matrix with constraints & animsys applied. */ float obmat[4][4]; /** Inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index eeff5473d16..634e97f782f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2066,6 +2066,9 @@ enum { #define SCE_SNAP_MODE_VOLUME (1 << 3) #define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4) #define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5) +#define SCE_SNAP_MODE_GEOM \ + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) /** #SequencerToolSettings.snap_mode */ #define SEQ_SNAP_TO_STRIPS (1 << 0) diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 607b00a833f..a4c254d6e5a 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -461,6 +461,9 @@ typedef struct ARegion_Runtime { /* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */ int offset_x, offset_y; + + /* Maps uiBlock->name to uiBlock for faster lookups. */ + struct GHash *block_name_map; } ARegion_Runtime; typedef struct ARegion { @@ -670,7 +673,7 @@ typedef enum eRegion_Type { RGN_TYPE_FOOTER = 11, RGN_TYPE_TOOL_HEADER = 12, /* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR - context (surface, mirror view). Does not represent any real region. */ + * context (surface, mirror view). Does not represent any real region. */ RGN_TYPE_XR = 13, #define RGN_TYPE_LEN (RGN_TYPE_XR + 1) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index fc23d3c69a3..9e6cf907444 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -378,7 +378,7 @@ typedef struct TextVars { char text[512]; struct VFont *text_font; int text_blf_id; - int text_size; + float text_size; float color[4], shadow_color[4], box_color[4]; float loc[2]; float wrap_width; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5ebc81fff4f..88c5ace9cb3 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -64,7 +64,7 @@ struct wmTimer; /* Defined in `buttons_intern.h`. */ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; -/* Defined in `node_intern.h`. */ +/* Defined in `node_intern.hh`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; /* Defined in `file_intern.h`. */ @@ -1158,8 +1158,12 @@ typedef struct FileDirEntryArr { /* FileDirEntry.flags */ enum { - FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */ + /* The preview for this entry could not be generated. */ + FILE_ENTRY_INVALID_PREVIEW = 1 << 0, + /* The entry name needs to be freed when clearing file list. */ FILE_ENTRY_NAME_FREE = 1 << 1, + /* The preview for this entry is being loaded on another thread. */ + FILE_ENTRY_PREVIEW_LOADING = 1 << 2, }; /** \} */ @@ -1516,6 +1520,7 @@ typedef struct SpaceNodeOverlay { typedef enum eSpaceNodeOverlay_Flag { SN_OVERLAY_SHOW_OVERLAYS = (1 << 1), SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2), + SN_OVERLAY_SHOW_TIMINGS = (1 << 3), } eSpaceNodeOverlay_Flag; typedef struct SpaceNode { @@ -2006,6 +2011,7 @@ typedef enum eSpreadsheetColumnValueType { SPREADSHEET_VALUE_TYPE_FLOAT3 = 4, SPREADSHEET_VALUE_TYPE_COLOR = 5, SPREADSHEET_VALUE_TYPE_INSTANCES = 6, + SPREADSHEET_VALUE_TYPE_STRING = 7, } eSpreadsheetColumnValueType; /** diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index ee33e8666ec..2c3cd8eab77 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -128,9 +128,9 @@ typedef struct PointDensity { struct Object *object; /** `index + 1` in ob.particlesystem, non-ID pointer not allowed */ int psys; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short psys_cache_space; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short ob_cache_space; /** vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */ char vertex_attribute_name[64]; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 104f335cd16..c8fdac19b61 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -69,8 +69,9 @@ typedef struct uiFont { typedef struct uiFontStyle { /** Saved in file, 0 is default. */ short uifont_id; + char _pad1[2]; /** Actual size depends on 'global' dpi. */ - short points; + float points; /** Style hint. */ short italic, bold; /** Value is amount of pixels blur. */ @@ -82,6 +83,7 @@ typedef struct uiFontStyle { float shadowalpha; /** 1 value, typically white or black anyway. */ float shadowcolor; + char _pad2[4]; } uiFontStyle; /* this is fed to the layout engine and widget code */ @@ -557,7 +559,7 @@ typedef struct bUserMenuItem_Op { bUserMenuItem item; char op_idname[64]; struct IDProperty *prop; - char opcontext; + char opcontext; /* #wmOperatorCallContext */ char _pad0[7]; } bUserMenuItem_Op; @@ -939,7 +941,8 @@ typedef struct UserDef { short sequencer_proxy_setup; /* eUserpref_SeqProxySetup */ float collection_instance_empty_size; - char _pad10[2]; + char text_flag; + char _pad10[1]; char file_preview_type; /* eUserpref_File_Preview_Type */ char statusbar_flag; /* eUserpref_StatusBar_Flag */ @@ -1264,6 +1267,14 @@ typedef enum eDupli_ID_Flags { } eDupli_ID_Flags; /** + * Text Editor options + * #UserDef.text_flag + */ +typedef enum eTextEdit_Flags { + USER_TEXT_EDIT_AUTO_CLOSE = (1 << 0), +} eTextEdit_Flags; + +/** * Text draw options * #UserDef.text_render */ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 9b5ed133feb..3fd2f1208dd 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -64,8 +64,10 @@ typedef struct RegionView3D { /** User defined clipping planes. */ float clip[6][4]; - /** Clip in object space, - * means we can test for clipping in editmode without first going into worldspace. */ + /** + * Clip in object space, + * means we can test for clipping in edit-mode without first going into world-space. + */ float clip_local[6][4]; struct BoundBox *clipbb; @@ -94,8 +96,8 @@ typedef struct RegionView3D { /** Runtime only. */ float pixsize; /** - * View center & orbit pivot, negative of worldspace location, - * also matches -viewinv[3][0:3] in ortho mode. + * View center & orbit pivot, negative of world-space location, + * also matches `-viewinv[3][0:3]` in orthographic mode. */ float ofs[3]; /** Viewport zoom on the camera frame, see BKE_screen_view3d_zoom_to_fac. */ diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h index f3e15d08fa3..fb18802483d 100644 --- a/source/blender/makesrna/RNA_enum_items.h +++ b/source/blender/makesrna/RNA_enum_items.h @@ -211,6 +211,8 @@ DEF_ENUM(rna_enum_attribute_domain_items) DEF_ENUM(rna_enum_attribute_domain_without_corner_items) DEF_ENUM(rna_enum_attribute_domain_with_auto_items) +DEF_ENUM(rna_enum_volume_grid_data_type_items) + DEF_ENUM(rna_enum_collection_color_items) DEF_ENUM(rna_enum_strip_color_items) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index f2e87b29c1f..a6732ca1760 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4698,6 +4698,19 @@ static const char *cpp_classes = " inline static int sname##_##identifier##_length_wrap(PointerRNA *ptr) \\\n" " { return sname##_##identifier##_length(ptr); } \n" "\n" + "#define COLLECTION_PROPERTY_EMPTY_false(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { \\\n" + " CollectionPropertyIterator iter; \\\n" + " sname##_##identifier##_begin(&iter, ptr); \\\n" + " bool empty = !iter.valid; \\\n" + " sname##_##identifier##_end(&iter); \\\n" + " return empty; \\\n" + " } \n" + "#define COLLECTION_PROPERTY_EMPTY_true(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { return sname##_##identifier##_length(ptr) == 0; } \n" + "\n" "#define COLLECTION_PROPERTY_LOOKUP_INT_false(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_int_wrap(PointerRNA *ptr, int key, " "PointerRNA *r_ptr) \\\n" @@ -4774,11 +4787,13 @@ static const char *cpp_classes = " typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n" " COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n" + " COLLECTION_PROPERTY_EMPTY_##has_length(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_INT_##has_lookup_int(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_STRING_##has_lookup_string(sname, identifier) \\\n" " CollectionRef<sname, type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end, \\\n" " sname##_##identifier##_length_wrap, \\\n" + " sname##_##identifier##_empty_wrap, \\\n" " sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, " "collection_funcs> identifier;\n" "\n" @@ -4844,6 +4859,7 @@ static const char *cpp_classes = "typedef void (*TNextFunc)(CollectionPropertyIterator *iter);\n" "typedef void (*TEndFunc)(CollectionPropertyIterator *iter);\n" "typedef int (*TLengthFunc)(PointerRNA *ptr);\n" + "typedef bool (*TEmptyFunc)(PointerRNA *ptr);\n" "typedef int (*TLookupIntFunc)(PointerRNA *ptr, int key, PointerRNA *r_ptr);\n" "typedef int (*TLookupStringFunc)(PointerRNA *ptr, const char *key, PointerRNA *r_ptr);\n" "\n" @@ -4882,8 +4898,8 @@ static const char *cpp_classes = "};\n" "\n" "template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n" - " TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n" - " typename Tcollection_funcs>\n" + " TLengthFunc Tlength, TEmptyFunc Tempty, TLookupIntFunc Tlookup_int,\n" + " TLookupStringFunc Tlookup_string, typename Tcollection_funcs>\n" "class CollectionRef : public Tcollection_funcs {\n" "public:\n" " CollectionRef(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n" @@ -4897,6 +4913,8 @@ static const char *cpp_classes = "" " int length()\n" " { return Tlength(&ptr); }\n" + " bool empty()\n" + " { return Tempty(&ptr); }\n" " T operator[](int key)\n" " { PointerRNA r_ptr; Tlookup_int(&ptr, key, &r_ptr); return T(r_ptr); }\n" " T operator[](const std::string &key)\n" diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index b205b3d7139..1511921cef0 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -117,7 +117,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) srna = RNA_def_struct(brna, "MotionPath", NULL); RNA_def_struct_sdna(srna, "bMotionPath"); RNA_def_struct_ui_text( - srna, "Motion Path", "Cache of the worldspace positions of an element over a frame range"); + srna, "Motion Path", "Cache of the world-space positions of an element over a frame range"); /* Collections */ prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index dbf20896463..78c15444308 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -72,6 +72,7 @@ const EnumPropertyItem rna_enum_attribute_domain_items[] = { /* Not implement yet */ // {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -80,6 +81,7 @@ const EnumPropertyItem rna_enum_attribute_domain_without_corner_items[] = { {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -90,6 +92,7 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = { {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 1d3b8cd9f9c..b4cf15ebfc6 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1283,7 +1283,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) static EnumPropertyItem gppaint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 7fe51d45eb2..82f3279146a 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -167,14 +167,14 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { #ifndef RNA_RUNTIME static const EnumPropertyItem modifier_modify_color_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem modifier_modify_opacity_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {GP_MODIFY_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"}, @@ -1450,7 +1450,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) static EnumPropertyItem tint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; @@ -2677,7 +2677,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) {STROKE_AND_FILL, "STROKE_AND_FILL", 0, - "Stroke and Fill", + "Stroke & Fill", "Manipulate both stroke and fill texture coordinates"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index e6b732aabd4..aef3823338b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -12754,6 +12754,11 @@ static void rna_def_nodetree(BlenderRNA *brna) PropertyRNA *parm; static const EnumPropertyItem static_type_items[] = { + {NTREE_UNDEFINED, + "UNDEFINED", + ICON_QUESTION, + "Undefined", + "Undefined type of nodes (can happen e.g. when a linked node tree goes missing)"}, {NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"}, {NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"}, {NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"}, diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 10094ade711..63c4774d0e5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -530,7 +530,7 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } -/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite +/* TODO(sergey): Make the Python API more clear that evaluation might happen, or require * passing fully evaluated depsgraph. */ static Object *eval_object_ensure(Object *ob, bContext *C, diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 186222d2ca0..2fca9f0af7a 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1006,8 +1006,7 @@ static void rna_def_pointcache_common(StructRNA *srna) prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, "", "Some frames were skipped while baking/saving that cache"); + RNA_def_property_ui_text(prop, "", "Some frames were skipped while baking/saving that cache"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 9f92f1c6e5f..f92043995dd 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1366,6 +1366,28 @@ static float rna_Sequence_fps_get(PointerRNA *ptr) return SEQ_time_sequence_get_fps(scene, seq); } +static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain) +{ + Scene *scene = (Scene *)id; + + /* Find the appropriate seqbase */ + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm); + + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) { + SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase); + } + + SEQ_edit_flag_for_removal(scene, seqbase, seqm); + SEQ_edit_remove_flagged_sequences(scene, seqbase); + + /* Update depsgraph. */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + + WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -2439,6 +2461,7 @@ static void rna_def_image(BlenderRNA *brna) static void rna_def_meta(BlenderRNA *brna) { StructRNA *srna; + FunctionRNA *func; PropertyRNA *prop; srna = RNA_def_struct(brna, "MetaSequence", "Sequence"); @@ -2452,6 +2475,10 @@ static void rna_def_meta(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip"); RNA_api_sequences(brna, prop, true); + func = RNA_def_function(srna, "separate", "rna_Sequence_separate"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_ui_description(func, "Separate meta"); + rna_def_filter_video(srna); rna_def_proxy(srna); rna_def_input(srna); @@ -2980,11 +3007,11 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_pointer_funcs(prop, NULL, "rna_Sequence_text_font_set", NULL, NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); - prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "text_size"); + prop = RNA_def_property(srna, "font_size", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "text_size"); RNA_def_property_ui_text(prop, "Size", "Size of the text"); RNA_def_property_range(prop, 0.0, 2000); - RNA_def_property_ui_range(prop, 0.0f, 2000, 1, -1); + RNA_def_property_ui_range(prop, 0.0f, 2000, 10.f, 1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 03976967e9f..8f04524c5c1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3090,7 +3090,7 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma break; } case GEO_COMPONENT_TYPE_INSTANCES: { - sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT; + sspreadsheet->attribute_domain = ATTR_DOMAIN_INSTANCE; break; } case GEO_COMPONENT_TYPE_VOLUME: { @@ -7110,6 +7110,12 @@ static void rna_def_space_node_overlay(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Show Wire Colors", "Color node links based on their connected sockets"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); + + prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS); + RNA_def_property_boolean_default(prop, false); + RNA_def_property_ui_text(prop, "Show Timing", "Display each node's last execution time"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); } static void rna_def_space_node(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index c73599c19ac..05ed5e096d8 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1471,15 +1471,12 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->category"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text( - prop, - "", - "The category (tab) in which the panel will be displayed, when applicable"); + prop, "", "The category (tab) in which the panel will be displayed, when applicable"); prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_ui_text( - prop, "", "The ID owning the data displayed in the panel, if any"); + RNA_def_property_ui_text(prop, "", "The ID owning the data displayed in the panel, if any"); prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->space_type"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4542f8fa1d7..dd1252ffebf 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -265,6 +265,14 @@ static void rna_userdef_theme_update(Main *bmain, Scene *scene, PointerRNA *ptr) rna_userdef_update(bmain, scene, ptr); } +static void rna_userdef_theme_text_style_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + const uiStyle *style = UI_style_get(); + BLF_default_size(style->widgetlabel.points); + + rna_userdef_update(bmain, scene, ptr); +} + static void rna_userdef_gizmo_update(Main *bmain, Scene *scene, PointerRNA *ptr) { WM_reinit_gizmomap_all(bmain); @@ -1134,39 +1142,40 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) RNA_def_struct_clear_flag(srna, STRUCT_UNDO); RNA_def_struct_ui_text(srna, "Font Style", "Theme settings for Font"); - prop = RNA_def_property(srna, "points", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 6, 24); + prop = RNA_def_property(srna, "points", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_range(prop, 6.0f, 32.0f); + RNA_def_property_ui_range(prop, 8.0f, 20.0f, 10.0f, 1); RNA_def_property_ui_text(prop, "Points", "Font size in points"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL); RNA_def_property_range(prop, 0, 5); RNA_def_property_ui_text(prop, "Shadow Size", "Shadow size (0, 3 and 5 supported)"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_offset_x", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "shadx"); RNA_def_property_range(prop, -10, 10); RNA_def_property_ui_text(prop, "Shadow X Offset", "Shadow offset in pixels"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_offset_y", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "shady"); RNA_def_property_range(prop, -10, 10); RNA_def_property_ui_text(prop, "Shadow Y Offset", "Shadow offset in pixels"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shadowalpha"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Shadow Alpha", ""); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_value", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shadowcolor"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Shadow Brightness", "Shadow color in gray value"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); } static void rna_def_userdef_theme_ui_style(BlenderRNA *brna) @@ -5022,6 +5031,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Collection Instance Empty Size", "Display size of the empty when new collection instances are created"); + /* Text Editor */ + + prop = RNA_def_property(srna, "use_text_edit_auto_close", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "text_flag", USER_TEXT_EDIT_AUTO_CLOSE); + RNA_def_property_ui_text( + prop, "Auto Close", "Auto close relevant characters inside the text editor"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); + /* Undo */ prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c index f6b8b55688c..3100c1195f4 100644 --- a/source/blender/makesrna/intern/rna_volume.c +++ b/source/blender/makesrna/intern/rna_volume.c @@ -33,6 +33,26 @@ #include "BLI_math_base.h" +const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = { + {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"}, + {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"}, + {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"}, + {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"}, + {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"}, + {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"}, + {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"}, + {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"}, + {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"}, + {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"}, + {VOLUME_GRID_POINTS, + "POINTS", + 0, + "Points (Unsupported)", + "Points grid, currently unsupported by volume objects"}, + {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DEG_depsgraph.h" @@ -244,30 +264,10 @@ static void rna_def_volume_grid(BlenderRNA *brna) prop, "rna_VolumeGrid_name_get", "rna_VolumeGrid_name_length", NULL); RNA_def_property_ui_text(prop, "Name", "Volume grid name"); - static const EnumPropertyItem data_type_items[] = { - {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"}, - {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"}, - {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"}, - {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"}, - {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"}, - {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"}, - {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"}, - {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"}, - {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"}, - {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"}, - {VOLUME_GRID_POINTS, - "POINTS", - 0, - "Points (Unsupported)", - "Points grid, currently unsupported by volume objects"}, - {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"}, - {0, NULL, 0, NULL, NULL}, - }; - prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_funcs(prop, "rna_VolumeGrid_data_type_get", NULL, NULL); - RNA_def_property_enum_items(prop, data_type_items); + RNA_def_property_enum_items(prop, rna_enum_volume_grid_data_type_items); RNA_def_property_ui_text(prop, "Data Type", "Data type of voxel values"); prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 1121e30b0ff..f8c181905b5 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -245,16 +245,16 @@ static BMesh *BMD_mesh_bm_create( const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob); - BMeshCreateParams bmcp = {false}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMeshCreateParams bmesh_create_params{}; + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`, * otherwise the wrong active render layer is used, see T92384. */ BM_mesh_copy_init_customdata_from_mesh(bm, mesh, &allocsize); - BMeshFromMeshParams params{}; - params.calc_face_normal = true; - BM_mesh_bm_from_me(bm, mesh_operand_ob, ¶ms); + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = true; + BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params); if (UNLIKELY(*r_is_flip)) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); @@ -265,7 +265,7 @@ static BMesh *BMD_mesh_bm_create( } } - BM_mesh_bm_from_me(bm, mesh, ¶ms); + BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params); return bm; } @@ -539,9 +539,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); /* Needed for multiple objects to work. */ - BMeshToMeshParams params{}; - params.calc_object_remap = false; - BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); + BMeshToMeshParams bmesh_to_mesh_params{}; + bmesh_to_mesh_params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); BM_mesh_free(bm); diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index c997cd7377f..cb043643dd9 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -426,7 +426,7 @@ static void meshdeformModifier_do(ModifierData *md, bindcagecos = (float(*)[3])mmd->bindcagecos; for (a = 0; a < totcagevert; a++) { - /* get cage vertex in world space with binding transform */ + /* Get cage vertex in world-space with binding transform. */ float co[3]; mul_v3_m4v3(co, mmd->bindmat, dco[a]); /* compute difference with world space bind coord */ diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c1cdfa43920..05e9bd7d233 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -98,6 +98,7 @@ #include "NOD_node_declaration.hh" #include "FN_field.hh" +#include "FN_field_cpp_type.hh" #include "FN_multi_function.hh" using blender::Array; @@ -113,9 +114,11 @@ using blender::StringRef; using blender::StringRefNull; using blender::Vector; using blender::bke::OutputAttribute; +using blender::fn::Field; using blender::fn::GField; using blender::fn::GMutablePointer; using blender::fn::GPointer; +using blender::fn::ValueOrField; using blender::nodes::FieldInferencingInterface; using blender::nodes::GeoNodeExecParams; using blender::nodes::InputSocketFieldType; @@ -491,35 +494,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property, else if (property.type == IDP_DOUBLE) { value = (float)IDP_Double(&property); } - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); break; } case SOCK_INT: { int value = IDP_Int(&property); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); break; } case SOCK_VECTOR: { float3 value; copy_v3_v3(value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float3>(value); break; } case SOCK_RGBA: { blender::ColorGeometry4f value; copy_v4_v4((float *)value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<ColorGeometry4f>(value); break; } case SOCK_BOOLEAN: { bool value = IDP_Int(&property) != 0; - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); break; } case SOCK_STRING: { std::string value = IDP_String(&property); - new (r_value) - blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value))); + new (r_value) ValueOrField<std::string>(std::move(value)); break; } case SOCK_OBJECT: { @@ -739,8 +741,13 @@ static void initialize_group_input(NodesModifierData &nmd, if (use_attribute) { const StringRef attribute_name{IDP_String(property_attribute_name)}; auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>( - attribute_name, *socket_type.get_base_cpp_type()); - new (r_value) blender::fn::GField(std::move(attribute_input), 0); + attribute_name, *socket_type.base_cpp_type); + GField attribute_field{std::move(attribute_input), 0}; + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>( + socket_type.geometry_nodes_cpp_type); + BLI_assert(cpp_type != nullptr); + cpp_type->construct_from_field(r_value, std::move(attribute_field)); } else { init_socket_cpp_value_from_property( @@ -904,7 +911,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set, if (attribute_name.is_empty()) { return; } - const GField &field = *(const GField *)value.get(); + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type()); + BLI_assert(cpp_type != nullptr); + + const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs, socket.index()); const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; @@ -963,7 +974,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, /* Initialize remaining group inputs. */ for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type(); + const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 094649baa87..0deef91d413 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -35,13 +35,17 @@ #include "BLI_task.hh" #include "BLI_vector_set.hh" +#include <chrono> + namespace blender::modifiers::geometry_nodes { using fn::CPPType; using fn::Field; -using fn::FieldCPPType; using fn::GField; using fn::GValueMap; +using fn::GVArray; +using fn::ValueOrField; +using fn::ValueOrFieldCPPType; using nodes::GeoNodeExecParams; using namespace fn::multi_function_types; @@ -309,10 +313,10 @@ class LockedNode : NonCopyable, NonMovable { static const CPPType *get_socket_cpp_type(const SocketRef &socket) { const bNodeSocketType *typeinfo = socket.typeinfo(); - if (typeinfo->get_geometry_nodes_cpp_type == nullptr) { + if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } - const CPPType *type = typeinfo->get_geometry_nodes_cpp_type(); + const CPPType *type = typeinfo->geometry_nodes_cpp_type; if (type == nullptr) { return nullptr; } @@ -348,18 +352,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" : "handle_right"; - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>(side)); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side)); return true; } - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position")); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position")); return true; } if (socket.typeinfo()->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { - new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>()); + new (r_value) + ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>())); return true; } - new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>()); + new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>())); return true; } } @@ -926,7 +931,13 @@ class GeometryNodesEvaluator { params.error_message_add(geo_log::NodeWarningType::Legacy, TIP_("Legacy node will be removed before Blender 4.0")); } + using Clock = std::chrono::steady_clock; + Clock::time_point begin = Clock::now(); bnode.typeinfo->geometry_node_execute(params); + Clock::time_point end = Clock::now(); + const std::chrono::microseconds duration = + std::chrono::duration_cast<std::chrono::microseconds>(end - begin); + params_.geo_logger->local().log_execution_time(node, duration); } void execute_multi_function_node(const DNode node, @@ -943,8 +954,9 @@ class GeometryNodesEvaluator { LinearAllocator<> &allocator = local_allocators_.local(); - /* Prepare the inputs for the multi function. */ - Vector<GField> input_fields; + bool any_input_is_field = false; + Vector<const void *, 16> input_values; + Vector<const ValueOrFieldCPPType *, 16> input_types; for (const int i : node->inputs().index_range()) { const InputSocketRef &socket_ref = node->input(i); if (!socket_ref.is_available()) { @@ -955,7 +967,37 @@ class GeometryNodesEvaluator { BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; BLI_assert(single_value.value != nullptr); - input_fields.append(std::move(*(GField *)single_value.value)); + const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>( + *input_state.type); + input_values.append(single_value.value); + input_types.append(&field_cpp_type); + if (field_cpp_type.is_field(single_value.value)) { + any_input_is_field = true; + } + } + + if (any_input_is_field) { + this->execute_multi_function_node__field( + node, fn_item, node_state, allocator, input_values, input_types); + } + else { + this->execute_multi_function_node__value( + node, *fn_item.fn, node_state, allocator, input_values, input_types); + } + } + + void execute_multi_function_node__field(const DNode node, + const nodes::NodeMultiFunctions::Item &fn_item, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + Vector<GField> input_fields; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + input_fields.append(field_cpp_type.as_field(input_value_or_field)); } std::shared_ptr<fn::FieldOperation> operation; @@ -966,7 +1008,6 @@ class GeometryNodesEvaluator { operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields)); } - /* Forward outputs. */ int output_index = 0; for (const int i : node->outputs().index_range()) { const OutputSocketRef &socket_ref = node->output(i); @@ -975,16 +1016,68 @@ class GeometryNodesEvaluator { } OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket{node.context(), &socket_ref}; - const CPPType *cpp_type = get_socket_cpp_type(socket_ref); + const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket_ref)); GField new_field{operation, output_index}; - new_field = fn::make_field_constant_if_possible(std::move(new_field)); - GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release(); - this->forward_output(socket, {cpp_type, &field_to_forward}); + void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); + cpp_type->construct_from_field(buffer, std::move(new_field)); + this->forward_output(socket, {cpp_type, buffer}); output_state.has_been_computed = true; output_index++; } } + void execute_multi_function_node__value(const DNode node, + const MultiFunction &fn, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + MFParamsBuilder params{fn, 1}; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + const CPPType &base_type = field_cpp_type.base_type(); + const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field); + params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value)); + } + + Vector<GMutablePointer, 16> output_buffers; + for (const int i : node->outputs().index_range()) { + const DOutputSocket socket = node.output(i); + if (!socket->is_available()) { + output_buffers.append({}); + continue; + } + const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket)); + const CPPType &base_type = value_or_field_type->base_type(); + void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(), + value_or_field_type->alignment()); + value_or_field_type->default_construct(value_or_field_buffer); + void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer); + base_type.destruct(value_buffer); + params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1}); + output_buffers.append({value_or_field_type, value_or_field_buffer}); + } + + MFContextBuilder context; + fn.call(IndexRange(1), params, context); + + for (const int i : output_buffers.index_range()) { + GMutablePointer buffer = output_buffers[i]; + if (buffer.get() == nullptr) { + continue; + } + const DOutputSocket socket = node.output(i); + this->forward_output(socket, buffer); + + OutputState &output_state = node_state.outputs[i]; + output_state.has_been_computed = true; + } + } + void execute_unknown_node(const DNode node, NodeState &node_state) { LinearAllocator<> &allocator = local_allocators_.local(); @@ -1482,19 +1575,28 @@ class GeometryNodesEvaluator { from_type.copy_construct(from_value, to_value); return; } - - const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type); - const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type); + const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>( + &from_type); + const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type); if (from_field_type != nullptr && to_field_type != nullptr) { - const CPPType &from_base_type = from_field_type->field_type(); - const CPPType &to_base_type = to_field_type->field_type(); + const CPPType &from_base_type = from_field_type->base_type(); + const CPPType &to_base_type = to_field_type->base_type(); if (conversions_.is_convertible(from_base_type, to_base_type)) { - const MultiFunction &fn = *conversions_.get_conversion_multi_function( - MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); - const GField &from_field = *(const GField *)from_value; - auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); - new (to_value) GField(std::move(operation), 0); + if (from_field_type->is_field(from_value)) { + const GField &from_field = *from_field_type->get_field_ptr(from_value); + const MultiFunction &fn = *conversions_.get_conversion_multi_function( + MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); + auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); + to_field_type->construct_from_field(to_value, GField(std::move(operation), 0)); + } + else { + to_field_type->default_construct(to_value); + const void *from_value_ptr = from_field_type->get_value_ptr(from_value); + void *to_value_ptr = to_field_type->get_value_ptr(to_value); + conversions_.get_conversion_functions(from_base_type, to_base_type) + ->convert_single_to_initialized(from_value_ptr, to_value_ptr); + } return; } } @@ -1510,14 +1612,6 @@ class GeometryNodesEvaluator { void construct_default_value(const CPPType &type, void *r_value) { - if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) { - const CPPType &base_type = field_cpp_type->field_type(); - auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>( - base_type, base_type.default_value(), false); - auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn)); - new (r_value) GField(std::move(operation), 0); - return; - } type.copy_construct(type.default_value(), r_value); } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 2c28e9710ef..238952fde00 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); - /* calculate worldspace projector normal (for best projector test) */ + /* Calculate world-space projector normal (for best projector test). */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; @@ -208,7 +208,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts); - /* convert coords to world space */ + /* Convert coords to world-space. */ for (i = 0, co = coords; i < numVerts; i++, co++) { mul_m4_v3(ob->obmat, *co); } diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index f4ca9f51b1b..e256ebcff56 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(geometry) + set(INC . composite @@ -39,6 +41,7 @@ set(INC ../makesdna ../makesrna ../render + ../windowmanager ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/sky/include @@ -154,148 +157,6 @@ set(SRC function/nodes/node_fn_value_to_string.cc function/node_function_util.cc - geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc - geometry/nodes/legacy/node_geo_attribute_clamp.cc - geometry/nodes/legacy/node_geo_attribute_color_ramp.cc - geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc - geometry/nodes/legacy/node_geo_attribute_compare.cc - geometry/nodes/legacy/node_geo_attribute_convert.cc - geometry/nodes/legacy/node_geo_attribute_curve_map.cc - geometry/nodes/legacy/node_geo_attribute_fill.cc - geometry/nodes/legacy/node_geo_attribute_map_range.cc - geometry/nodes/legacy/node_geo_attribute_math.cc - geometry/nodes/legacy/node_geo_attribute_mix.cc - geometry/nodes/legacy/node_geo_attribute_proximity.cc - geometry/nodes/legacy/node_geo_attribute_randomize.cc - geometry/nodes/legacy/node_geo_attribute_sample_texture.cc - geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc - geometry/nodes/legacy/node_geo_attribute_transfer.cc - geometry/nodes/legacy/node_geo_attribute_vector_math.cc - geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc - geometry/nodes/legacy/node_geo_curve_endpoints.cc - geometry/nodes/legacy/node_geo_curve_reverse.cc - geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc - geometry/nodes/legacy/node_geo_curve_set_handles.cc - geometry/nodes/legacy/node_geo_curve_spline_type.cc - geometry/nodes/legacy/node_geo_curve_subdivide.cc - geometry/nodes/legacy/node_geo_curve_to_points.cc - geometry/nodes/legacy/node_geo_delete_geometry.cc - geometry/nodes/legacy/node_geo_edge_split.cc - geometry/nodes/legacy/node_geo_material_assign.cc - geometry/nodes/legacy/node_geo_mesh_to_curve.cc - geometry/nodes/legacy/node_geo_point_distribute.cc - geometry/nodes/legacy/node_geo_point_instance.cc - geometry/nodes/legacy/node_geo_point_rotate.cc - geometry/nodes/legacy/node_geo_point_scale.cc - geometry/nodes/legacy/node_geo_point_separate.cc - geometry/nodes/legacy/node_geo_point_translate.cc - geometry/nodes/legacy/node_geo_points_to_volume.cc - geometry/nodes/legacy/node_geo_raycast.cc - geometry/nodes/legacy/node_geo_select_by_material.cc - geometry/nodes/legacy/node_geo_subdivision_surface.cc - geometry/nodes/legacy/node_geo_volume_to_mesh.cc - - geometry/nodes/node_geo_attribute_capture.cc - geometry/nodes/node_geo_attribute_remove.cc - geometry/nodes/node_geo_attribute_statistic.cc - geometry/nodes/node_geo_boolean.cc - geometry/nodes/node_geo_bounding_box.cc - geometry/nodes/node_geo_collection_info.cc - geometry/nodes/node_geo_common.cc - geometry/nodes/node_geo_convex_hull.cc - geometry/nodes/node_geo_curve_endpoint_selection.cc - geometry/nodes/node_geo_curve_fill.cc - geometry/nodes/node_geo_curve_fillet.cc - geometry/nodes/node_geo_curve_handle_type_selection.cc - geometry/nodes/node_geo_curve_length.cc - geometry/nodes/node_geo_curve_parameter.cc - geometry/nodes/node_geo_curve_primitive_bezier_segment.cc - geometry/nodes/node_geo_curve_primitive_circle.cc - geometry/nodes/node_geo_curve_primitive_line.cc - geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc - geometry/nodes/node_geo_curve_primitive_quadrilateral.cc - geometry/nodes/node_geo_curve_primitive_spiral.cc - geometry/nodes/node_geo_curve_primitive_star.cc - geometry/nodes/node_geo_curve_resample.cc - geometry/nodes/node_geo_curve_reverse.cc - geometry/nodes/node_geo_curve_sample.cc - geometry/nodes/node_geo_curve_set_handles.cc - geometry/nodes/node_geo_curve_spline_type.cc - geometry/nodes/node_geo_curve_subdivide.cc - geometry/nodes/node_geo_curve_to_mesh.cc - geometry/nodes/node_geo_curve_to_points.cc - geometry/nodes/node_geo_curve_trim.cc - geometry/nodes/node_geo_delete_geometry.cc - geometry/nodes/node_geo_distribute_points_on_faces.cc - geometry/nodes/node_geo_edge_split.cc - geometry/nodes/node_geo_image_texture.cc - geometry/nodes/node_geo_input_curve_handles.cc - geometry/nodes/node_geo_input_curve_tilt.cc - geometry/nodes/node_geo_input_id.cc - geometry/nodes/node_geo_input_index.cc - geometry/nodes/node_geo_input_material_index.cc - geometry/nodes/node_geo_input_material.cc - geometry/nodes/node_geo_input_normal.cc - geometry/nodes/node_geo_input_position.cc - geometry/nodes/node_geo_input_radius.cc - geometry/nodes/node_geo_input_shade_smooth.cc - geometry/nodes/node_geo_input_spline_cyclic.cc - geometry/nodes/node_geo_input_spline_length.cc - geometry/nodes/node_geo_input_spline_resolution.cc - geometry/nodes/node_geo_input_tangent.cc - geometry/nodes/node_geo_instance_on_points.cc - geometry/nodes/node_geo_instances_to_points.cc - geometry/nodes/node_geo_is_viewport.cc - geometry/nodes/node_geo_join_geometry.cc - geometry/nodes/node_geo_material_replace.cc - geometry/nodes/node_geo_material_selection.cc - geometry/nodes/node_geo_mesh_primitive_circle.cc - geometry/nodes/node_geo_mesh_primitive_cone.cc - geometry/nodes/node_geo_mesh_primitive_cube.cc - geometry/nodes/node_geo_mesh_primitive_cylinder.cc - geometry/nodes/node_geo_mesh_primitive_grid.cc - geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc - geometry/nodes/node_geo_mesh_primitive_line.cc - geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc - geometry/nodes/node_geo_mesh_subdivide.cc - geometry/nodes/node_geo_mesh_to_curve.cc - geometry/nodes/node_geo_mesh_to_points.cc - geometry/nodes/node_geo_object_info.cc - geometry/nodes/node_geo_points_to_vertices.cc - geometry/nodes/node_geo_points_to_volume.cc - geometry/nodes/node_geo_proximity.cc - geometry/nodes/node_geo_raycast.cc - geometry/nodes/node_geo_realize_instances.cc - geometry/nodes/node_geo_rotate_instances.cc - geometry/nodes/node_geo_scale_instances.cc - geometry/nodes/node_geo_separate_components.cc - geometry/nodes/node_geo_separate_geometry.cc - geometry/nodes/node_geo_set_curve_handles.cc - geometry/nodes/node_geo_set_curve_radius.cc - geometry/nodes/node_geo_set_curve_tilt.cc - geometry/nodes/node_geo_set_id.cc - geometry/nodes/node_geo_set_material_index.cc - geometry/nodes/node_geo_set_material.cc - geometry/nodes/node_geo_set_point_radius.cc - geometry/nodes/node_geo_set_position.cc - geometry/nodes/node_geo_set_shade_smooth.cc - geometry/nodes/node_geo_set_spline_cyclic.cc - geometry/nodes/node_geo_set_spline_resolution.cc - geometry/nodes/node_geo_string_join.cc - geometry/nodes/node_geo_string_to_curves.cc - geometry/nodes/node_geo_subdivision_surface.cc - geometry/nodes/node_geo_switch.cc - geometry/nodes/node_geo_transfer_attribute.cc - geometry/nodes/node_geo_transform.cc - geometry/nodes/node_geo_translate_instances.cc - geometry/nodes/node_geo_triangulate.cc - geometry/nodes/node_geo_viewer.cc - geometry/nodes/node_geo_volume_to_mesh.cc - - geometry/node_geometry_exec.cc - geometry/node_geometry_tree.cc - geometry/node_geometry_util.cc - shader/nodes/node_shader_add_shader.c shader/nodes/node_shader_ambient_occlusion.c shader/nodes/node_shader_attribute.c @@ -433,7 +294,6 @@ set(SRC composite/node_composite_util.hh function/node_function_util.hh shader/node_shader_util.h - geometry/node_geometry_util.hh texture/node_texture_util.h NOD_common.h @@ -462,8 +322,8 @@ set(SRC set(LIB bf_bmesh bf_functions - bf_geometry bf_intern_sky + bf_nodes_geometry ) if(WITH_BULLET) diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index 50ed992dcb6..fa979bb4799 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -45,6 +45,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char void node_group_input_update(struct bNodeTree *ntree, struct bNode *node); void node_group_output_update(struct bNodeTree *ntree, struct bNode *node); +void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node); + #ifdef __cplusplus } #endif diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 6e1f21dbae0..6b6e8a89240 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -57,13 +57,9 @@ using fn::GPointer; using fn::GSpan; using fn::GVArray; using fn::GVArray_GSpan; -using fn::GVArray_Span; -using fn::GVArray_Typed; -using fn::GVArrayPtr; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; -using fn::GVMutableArray_Typed; -using fn::GVMutableArrayPtr; +using fn::ValueOrField; using geometry_nodes_eval_log::NodeWarningType; /** @@ -134,7 +130,7 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, bool> || std::is_same_v<T, ColorGeometry4f> || @@ -162,9 +158,15 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { - if constexpr (is_stored_as_field_v<T>) { - Field<T> field = this->extract_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>( + identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -191,9 +193,9 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> field = gvalue.relocate_out<Field<T>>(); - values.append(fn::evaluate_constant_field(field)); + if constexpr (is_field_base_type_v<T>) { + const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>(); + values.append(value_or_field.as_value()); } else { values.append(gvalue.relocate_out<T>()); @@ -205,11 +207,16 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T get_input(StringRef identifier) const + template<typename T> T get_input(StringRef identifier) const { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> &field = this->get_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -231,9 +238,12 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - if constexpr (is_stored_as_field_v<StoredT>) { - this->set_output<Field<StoredT>>(identifier, - fn::make_constant_field<StoredT>(std::forward<T>(value))); + if constexpr (is_field_base_type_v<StoredT>) { + this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value))); + } + else if constexpr (fn::is_field_v<StoredT>) { + using BaseType = typename StoredT::base_type; + this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value))); } else { const CPPType &type = CPPType::get<StoredT>(); @@ -316,21 +326,21 @@ class GeoNodeExecParams { * \note This will add an error message if the string socket is active and * the input attribute does not exist. */ - GVArrayPtr get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const; + GVArray get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const; template<typename T> - GVArray_Typed<T> get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const T &default_value) const + VArray<T> get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const T &default_value) const { const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); - GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value); - return GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value); + return varray.typed<T>(); } /** diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index 2a118057a03..0fbc1803db6 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -41,6 +41,8 @@ #include "NOD_derived_node_tree.hh" +#include <chrono> + struct SpaceNode; struct SpaceSpreadsheet; @@ -169,6 +171,11 @@ struct NodeWithWarning { NodeWarning warning; }; +struct NodeWithExecutionTime { + DNode node; + std::chrono::microseconds exec_time; +}; + /** The same value can be referenced by multiple sockets when they are linked. */ struct ValueOfSockets { Span<DSocket> sockets; @@ -189,6 +196,7 @@ class LocalGeoLogger { std::unique_ptr<LinearAllocator<>> allocator_; Vector<ValueOfSockets> values_; Vector<NodeWithWarning> node_warnings_; + Vector<NodeWithExecutionTime> node_exec_times_; friend ModifierLog; @@ -201,6 +209,7 @@ class LocalGeoLogger { void log_value_for_sockets(Span<DSocket> sockets, GPointer value); void log_multi_value_socket(DSocket socket, Span<GPointer> values); void log_node_warning(DNode node, NodeWarningType type, std::string message); + void log_execution_time(DNode node, std::chrono::microseconds exec_time); }; /** The root logger class. */ @@ -274,12 +283,14 @@ class NodeLog { Vector<SocketLog> input_logs_; Vector<SocketLog> output_logs_; Vector<NodeWarning, 0> warnings_; + std::chrono::microseconds exec_time_; friend ModifierLog; public: const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const; const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const; + void execution_time(std::chrono::microseconds exec_time); Span<SocketLog> input_logs() const { @@ -296,6 +307,11 @@ class NodeLog { return warnings_; } + std::chrono::microseconds execution_time() const + { + return exec_time_; + } + Vector<const GeometryAttributeInfo *> lookup_available_attributes() const; }; diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index e9f2996bb30..9b99026d6a7 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -228,7 +228,6 @@ class NodeDeclaration { friend NodeDeclarationBuilder; public: - void build(bNodeTree &ntree, bNode &node) const; bool matches(const bNode &node) const; Span<SocketDeclarationPtr> inputs() const; diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh index ec4859f0657..c8b24fd1260 100644 --- a/source/blender/nodes/NOD_type_conversions.hh +++ b/source/blender/nodes/NOD_type_conversions.hh @@ -21,7 +21,6 @@ namespace blender::nodes { using fn::CPPType; -using fn::GVArray; struct ConversionFunctions { const fn::MultiFunction *multi_function; @@ -73,9 +72,9 @@ class DataTypeConversions { const void *from_value, void *to_value) const; - fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const; + fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const; - fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const; + fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const; }; const DataTypeConversions &get_implicit_type_conversions(); diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc index 86aaec61bc3..21269b92e65 100644 --- a/source/blender/nodes/composite/node_composite_util.cc +++ b/source/blender/nodes/composite/node_composite_util.cc @@ -52,5 +52,4 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index fecf6795ef7..6432a89ffa0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -44,7 +44,6 @@ void register_node_type_cmp_group(void) ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -66,7 +65,4 @@ void register_node_type_cmp_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index 4247e81e9b2..a1a49133a3a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -43,8 +43,7 @@ void register_node_type_cmp_composite(void) cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_composite_declare; - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 79cb0bd0f8c..40d4d4563c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -372,7 +372,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) { sock_next = sock->next; if (BLI_linklist_index(available_sockets.list, sock) >= 0) { - sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN); + sock->flag &= ~SOCK_HIDDEN; + nodeSetSocketAvailability(ntree, sock, true); } else { bNodeLink *link; @@ -386,7 +387,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl nodeRemoveSocket(ntree, node, sock); } else { - sock->flag |= SOCK_UNAVAIL; + nodeSetSocketAvailability(ntree, sock, false); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index 3972fc0d949..284d16b9b0d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -32,7 +32,7 @@ static bNodeSocketTemplate cmp_node_scale_in[] = { {-1, ""}}; static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; -static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) +static void node_composite_update_scale(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE); @@ -40,12 +40,7 @@ static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) /* Only show X/Y scale factor inputs for modes using them! */ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { if (STR_ELEM(sock->name, "X", "Y")) { - if (use_xy_scale) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, use_xy_scale); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc index 68c5ecdf48e..c0403a041db 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc @@ -53,8 +53,7 @@ void register_node_type_cmp_splitviewer(void) node_type_init(&ntype, node_composit_init_splitviewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index 969e2409898..90f9882099b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -59,7 +59,7 @@ void register_node_type_cmp_viewer(void) node_type_init(&ntype, node_composit_init_viewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc index 8ff8b416310..a1493d51a11 100644 --- a/source/blender/nodes/function/node_function_util.cc +++ b/source/blender/nodes/function/node_function_util.cc @@ -33,6 +33,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas { node_type_base(ntype, type, name, nclass, flag); ntype->poll = fn_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b44e8d54ff1..ed03cc0025d 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -39,12 +39,12 @@ static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_boolean_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sockB, - ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); + nodeSetSocketAvailability( + ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); } static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index 2e1f2aaeeef..b31611a1df2 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -42,12 +42,14 @@ static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_float_compare_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2); nodeSetSocketAvailability( - sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); + ntree, + sockEpsilon, + ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); } static void node_float_compare_label(bNodeTree *UNUSED(ntree), diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc index d48b9f3461a..9720a39b740 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -63,7 +63,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) { const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -81,18 +81,18 @@ static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *sock_out_int = sock_out_float->next; bNodeSocket *sock_out_bool = sock_out_int->next; - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL); - - nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_probability, data_type == CD_PROP_BOOL); + + nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL); } class RandomVectorFunction : public fn::MultiFunction { diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index fc4c3d8221f..7dbc11fb161 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -36,18 +36,18 @@ static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Rotation")); }; -static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_rotate_euler_update(bNodeTree *ntree, bNode *node) { bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1)); bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2)); bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3)); - nodeSetSocketAvailability(rotate_by_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); - nodeSetSocketAvailability(axis_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); - nodeSetSocketAvailability(angle_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, rotate_by_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); + nodeSetSocketAvailability( + ntree, axis_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, angle_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); } static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt new file mode 100644 index 00000000000..61b5bbf6e7e --- /dev/null +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -0,0 +1,267 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../editors/include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../functions + ../../geometry + ../../gpu + ../../imbuf + ../../makesdna + ../../makesrna + ../../render + ../../windowmanager + ../../../../intern/guardedalloc +) + + +set(SRC + nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc + nodes/legacy/node_geo_legacy_attribute_clamp.cc + nodes/legacy/node_geo_legacy_attribute_color_ramp.cc + nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc + nodes/legacy/node_geo_legacy_attribute_compare.cc + nodes/legacy/node_geo_legacy_attribute_convert.cc + nodes/legacy/node_geo_legacy_attribute_curve_map.cc + nodes/legacy/node_geo_legacy_attribute_fill.cc + nodes/legacy/node_geo_legacy_attribute_map_range.cc + nodes/legacy/node_geo_legacy_attribute_math.cc + nodes/legacy/node_geo_legacy_attribute_mix.cc + nodes/legacy/node_geo_legacy_attribute_proximity.cc + nodes/legacy/node_geo_legacy_attribute_randomize.cc + nodes/legacy/node_geo_legacy_attribute_sample_texture.cc + nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc + nodes/legacy/node_geo_legacy_attribute_transfer.cc + nodes/legacy/node_geo_legacy_attribute_vector_math.cc + nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc + nodes/legacy/node_geo_legacy_curve_endpoints.cc + nodes/legacy/node_geo_legacy_curve_reverse.cc + nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc + nodes/legacy/node_geo_legacy_curve_set_handles.cc + nodes/legacy/node_geo_legacy_curve_spline_type.cc + nodes/legacy/node_geo_legacy_curve_subdivide.cc + nodes/legacy/node_geo_legacy_curve_to_points.cc + nodes/legacy/node_geo_legacy_delete_geometry.cc + nodes/legacy/node_geo_legacy_edge_split.cc + nodes/legacy/node_geo_legacy_material_assign.cc + nodes/legacy/node_geo_legacy_mesh_to_curve.cc + nodes/legacy/node_geo_legacy_point_distribute.cc + nodes/legacy/node_geo_legacy_point_instance.cc + nodes/legacy/node_geo_legacy_point_rotate.cc + nodes/legacy/node_geo_legacy_point_scale.cc + nodes/legacy/node_geo_legacy_point_separate.cc + nodes/legacy/node_geo_legacy_point_translate.cc + nodes/legacy/node_geo_legacy_points_to_volume.cc + nodes/legacy/node_geo_legacy_raycast.cc + nodes/legacy/node_geo_legacy_select_by_material.cc + nodes/legacy/node_geo_legacy_subdivision_surface.cc + nodes/legacy/node_geo_legacy_volume_to_mesh.cc + + nodes/node_geo_attribute_capture.cc + nodes/node_geo_attribute_remove.cc + nodes/node_geo_attribute_statistic.cc + nodes/node_geo_boolean.cc + nodes/node_geo_bounding_box.cc + nodes/node_geo_collection_info.cc + nodes/node_geo_common.cc + nodes/node_geo_convex_hull.cc + nodes/node_geo_curve_endpoint_selection.cc + nodes/node_geo_curve_fill.cc + nodes/node_geo_curve_fillet.cc + nodes/node_geo_curve_handle_type_selection.cc + nodes/node_geo_curve_length.cc + nodes/node_geo_curve_parameter.cc + nodes/node_geo_curve_primitive_bezier_segment.cc + nodes/node_geo_curve_primitive_circle.cc + nodes/node_geo_curve_primitive_line.cc + nodes/node_geo_curve_primitive_quadratic_bezier.cc + nodes/node_geo_curve_primitive_quadrilateral.cc + nodes/node_geo_curve_primitive_spiral.cc + nodes/node_geo_curve_primitive_star.cc + nodes/node_geo_curve_resample.cc + nodes/node_geo_curve_reverse.cc + nodes/node_geo_curve_sample.cc + nodes/node_geo_curve_set_handles.cc + nodes/node_geo_curve_spline_type.cc + nodes/node_geo_curve_subdivide.cc + nodes/node_geo_curve_to_mesh.cc + nodes/node_geo_curve_to_points.cc + nodes/node_geo_curve_trim.cc + nodes/node_geo_delete_geometry.cc + nodes/node_geo_distribute_points_on_faces.cc + nodes/node_geo_edge_split.cc + nodes/node_geo_image_texture.cc + nodes/node_geo_input_curve_handles.cc + nodes/node_geo_input_curve_tilt.cc + nodes/node_geo_input_id.cc + nodes/node_geo_input_index.cc + nodes/node_geo_input_material_index.cc + nodes/node_geo_input_material.cc + nodes/node_geo_input_normal.cc + nodes/node_geo_input_position.cc + nodes/node_geo_input_radius.cc + nodes/node_geo_input_shade_smooth.cc + nodes/node_geo_input_spline_cyclic.cc + nodes/node_geo_input_spline_length.cc + nodes/node_geo_input_spline_resolution.cc + nodes/node_geo_input_tangent.cc + nodes/node_geo_instance_on_points.cc + nodes/node_geo_instances_to_points.cc + nodes/node_geo_is_viewport.cc + nodes/node_geo_join_geometry.cc + nodes/node_geo_material_replace.cc + nodes/node_geo_material_selection.cc + nodes/node_geo_mesh_primitive_circle.cc + nodes/node_geo_mesh_primitive_cone.cc + nodes/node_geo_mesh_primitive_cube.cc + nodes/node_geo_mesh_primitive_cylinder.cc + nodes/node_geo_mesh_primitive_grid.cc + nodes/node_geo_mesh_primitive_ico_sphere.cc + nodes/node_geo_mesh_primitive_line.cc + nodes/node_geo_mesh_primitive_uv_sphere.cc + nodes/node_geo_mesh_subdivide.cc + nodes/node_geo_mesh_to_curve.cc + nodes/node_geo_mesh_to_points.cc + nodes/node_geo_object_info.cc + nodes/node_geo_points_to_vertices.cc + nodes/node_geo_points_to_volume.cc + nodes/node_geo_proximity.cc + nodes/node_geo_raycast.cc + nodes/node_geo_realize_instances.cc + nodes/node_geo_rotate_instances.cc + nodes/node_geo_scale_instances.cc + nodes/node_geo_separate_components.cc + nodes/node_geo_separate_geometry.cc + nodes/node_geo_set_curve_handles.cc + nodes/node_geo_set_curve_radius.cc + nodes/node_geo_set_curve_tilt.cc + nodes/node_geo_set_id.cc + nodes/node_geo_set_material_index.cc + nodes/node_geo_set_material.cc + nodes/node_geo_set_point_radius.cc + nodes/node_geo_set_position.cc + nodes/node_geo_set_shade_smooth.cc + nodes/node_geo_set_spline_cyclic.cc + nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_string_join.cc + nodes/node_geo_string_to_curves.cc + nodes/node_geo_subdivision_surface.cc + nodes/node_geo_switch.cc + nodes/node_geo_transfer_attribute.cc + nodes/node_geo_transform.cc + nodes/node_geo_translate_instances.cc + nodes/node_geo_triangulate.cc + nodes/node_geo_viewer.cc + nodes/node_geo_volume_to_mesh.cc + + node_geometry_exec.cc + node_geometry_tree.cc + node_geometry_util.cc + + node_geometry_util.hh +) + +set(LIB + bf_bmesh + bf_functions + bf_geometry +) + +if(WITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + "../../../../intern/rigidbody/" + ) + if(NOT WITH_SYSTEM_BULLET) + list(APPEND LIB + extern_bullet + ) + endif() + + list(APPEND LIB + ${BULLET_LIBRARIES} + ) + add_definitions(-DWITH_BULLET) +endif() + +if(WITH_PYTHON) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) + list(APPEND LIB + ${PYTHON_LINKFLAGS} + ${PYTHON_LIBRARIES} + ) + add_definitions(-DWITH_PYTHON) +endif() + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_TBB) + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() +endif() + +if(WITH_IMAGE_OPENEXR) + add_definitions(-DWITH_OPENEXR) +endif() + +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + +if(WITH_GMP) + add_definitions(-DWITH_GMP) + + list(APPEND INC_SYS + ${GMP_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${GMP_LIBRARIES} + ) +endif() + +if(WITH_OPENVDB) + list(APPEND INC_SYS + ${OPENVDB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) +endif() + +blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 46e9d36c09c..5c1d507041c 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -35,7 +35,8 @@ using bke::GeometryInstanceGroup; * \param mode: Controls which socket of the group to make available. * \param name_is_available: If false, make all sockets with this name unavailable. */ -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available) @@ -50,7 +51,7 @@ void update_attribute_input_socket_availabilities(bNode &node, (socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) || (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) || (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR)); - nodeSetSocketAvailability(socket, socket_is_available); + nodeSetSocketAvailability(&ntree, socket, socket_is_available); } } } @@ -72,6 +73,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla { node_type_base(ntype, type, name, nclass, flag); ntype->poll = geo_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 167765fa131..79fe2ffc42b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -43,7 +43,8 @@ bool geo_node_poll_default(struct bNodeType *ntype, const char **r_disabled_hint); namespace blender::nodes { -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available = true); @@ -67,13 +68,20 @@ Mesh *create_grid_mesh(const int verts_x, const float size_x, const float size_y); +struct ConeAttributeOutputs { + StrongAnonymousAttributeID top_id; + StrongAnonymousAttributeID bottom_id; + StrongAnonymousAttributeID side_id; +}; + Mesh *create_cylinder_or_cone_mesh(const float radius_top, const float radius_bottom, const float depth, const int circle_segments, const int side_segments, const int fill_segments, - const GeometryNodeMeshCircleFillType fill_type); + const GeometryNodeMeshCircleFillType fill_type, + ConeAttributeOutputs &attribute_outputs); Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc index b92d4704d63..5a5b0dbee9a 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc { -static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -40,9 +40,7 @@ static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -53,7 +51,7 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE); } -static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__); @@ -65,14 +63,14 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo node->storage = node_storage; } -static void geo_node_align_rotation_to_vector_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); } static void align_rotations_auto_pivot(const VArray<float3> &vectors, @@ -179,9 +177,9 @@ static void align_rotations_on_component(GeometryComponent &component, return; } - GVArray_Typed<float> factors = params.get_input_attribute<float>( + VArray<float> factors = params.get_input_attribute<float>( "Factor", component, ATTR_DOMAIN_POINT, 1.0f); - GVArray_Typed<float3> vectors = params.get_input_attribute<float3>( + VArray<float3> vectors = params.get_input_attribute<float3>( "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1}); float3 local_main_axis{0, 0, 0}; @@ -199,7 +197,7 @@ static void align_rotations_on_component(GeometryComponent &component, rotations.save(); } -static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -219,10 +217,12 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc void register_node_type_geo_align_rotation_to_vector() { + namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -230,14 +230,14 @@ void register_node_type_geo_align_rotation_to_vector() "Align Rotation to Vector", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init); - node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryAlignRotationToVector", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec; - ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc index 91ff114a480..40af5b7ec82 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_clamp_cc { -static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -38,13 +38,13 @@ static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), __func__); @@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -66,14 +66,14 @@ static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *nod const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_max_color, data_type == CD_PROP_COLOR); } template<typename T> T clamp_value(const T val, const T min, const T max); @@ -156,7 +156,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); const int operation = static_cast<int>(storage.operation); - GVArrayPtr attribute_input = component.attribute_try_get_for_read( + GVArray attribute_input = component.attribute_try_get_for_read( attribute_name, domain, data_type); OutputAttribute attribute_result = component.attribute_try_get_for_output_only( @@ -185,7 +185,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } } MutableSpan<float3> results = attribute_result.as_span<float3>(); - clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max); + clamp_attribute<float3>(attribute_input.typed<float3>(), results, min, max); break; } case CD_PROP_FLOAT: { @@ -193,10 +193,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const float max = params.get_input<float>("Max_001"); MutableSpan<float> results = attribute_result.as_span<float>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<float>(attribute_input->typed<float>(), results, max, min); + clamp_attribute<float>(attribute_input.typed<float>(), results, max, min); } else { - clamp_attribute<float>(attribute_input->typed<float>(), results, min, max); + clamp_attribute<float>(attribute_input.typed<float>(), results, min, max); } break; } @@ -205,10 +205,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const int max = params.get_input<int>("Max_002"); MutableSpan<int> results = attribute_result.as_span<int>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<int>(attribute_input->typed<int>(), results, max, min); + clamp_attribute<int>(attribute_input.typed<int>(), results, max, min); } else { - clamp_attribute<int>(attribute_input->typed<int>(), results, min, max); + clamp_attribute<int>(attribute_input.typed<int>(), results, min, max); } break; } @@ -231,7 +231,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); clamp_attribute<ColorGeometry4f>( - attribute_input->typed<ColorGeometry4f>(), results, min, max); + attribute_input.typed<ColorGeometry4f>(), results, min, max); break; } default: { @@ -243,7 +243,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam attribute_result.save(); } -static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -262,19 +262,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc void register_node_type_geo_attribute_clamp() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update); - ntype.declare = blender::nodes::geo_node_attribute_clamp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc index ab4b6aad545..66790acb712 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc { -static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -33,14 +33,12 @@ static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_color_ramp_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiTemplateColorRamp(layout, ptr, "color_ramp", false); } -static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( sizeof(NodeAttributeColorRamp), __func__); @@ -85,7 +83,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon return; } - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, 0.0f); MutableSpan<ColorGeometry4f> results = attribute_result.as_span(); @@ -100,7 +98,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -119,10 +117,12 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc void register_node_type_geo_attribute_color_ramp() { + namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,10 +132,10 @@ void register_node_type_geo_attribute_color_ramp() 0); node_type_storage( &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc index d4c23380b4e..f8320c57f92 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc { -static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("X")); @@ -34,9 +34,7 @@ static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -46,7 +44,7 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE); } -static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN( sizeof(NodeAttributeCombineXYZ), __func__); @@ -57,15 +55,15 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode * node->storage = data; } -static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); + *ntree, *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); update_attribute_input_socket_availabilities( - *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); + *ntree, *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); update_attribute_input_socket_availabilities( - *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); + *ntree, *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); } static AttributeDomain get_result_domain(const GeometryComponent &component, @@ -95,11 +93,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa if (!attribute_result) { return; } - GVArray_Typed<float> attribute_x = params.get_input_attribute<float>( + VArray<float> attribute_x = params.get_input_attribute<float>( "X", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_y = params.get_input_attribute<float>( + VArray<float> attribute_y = params.get_input_attribute<float>( "Y", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_z = params.get_input_attribute<float>( + VArray<float> attribute_z = params.get_input_attribute<float>( "Z", component, result_domain, 0.0f); for (const int i : IndexRange(attribute_result->size())) { @@ -111,7 +109,7 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa attribute_result.save(); } -static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -130,10 +128,12 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc void register_node_type_geo_attribute_combine_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -141,13 +141,13 @@ void register_node_type_geo_attribute_combine_xyz() "Attribute Combine XYZ", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc index e4e43a7b724..e64f41cca72 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_compare_cc { -static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -39,9 +39,7 @@ static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_compare_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -50,7 +48,7 @@ static void geo_node_attribute_compare_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare), __func__); @@ -65,16 +63,16 @@ static bool operation_tests_equality(const NodeAttributeCompare &node_storage) return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL); } -static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9); - nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage)); + nodeSetSocketAvailability(ntree, socket_threshold, operation_tests_equality(*node_storage)); } static void do_math_operation(const VArray<float> &input_a, @@ -257,9 +255,9 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx const CustomDataType input_data_type = get_data_type(component, params, *node_storage); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, input_data_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, input_data_type, nullptr); if (!attribute_a || !attribute_b) { @@ -276,53 +274,53 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx if (operation == NODE_FLOAT_COMPARE_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_not_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_not_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_not_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_not_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } } else { do_math_operation( - attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), operation, result_span); } attribute_result.save(); } -static void geo_node_attribute_compare_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -341,20 +339,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc void register_node_type_geo_attribute_compare() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_compare_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout; - node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init); + node_type_init(&ntype, file_ns::node_init); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc index dc05fa2c125..1f241e1f20e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_convert_cc { -static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -29,9 +29,7 @@ static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_convert_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -39,7 +37,7 @@ static void geo_node_attribute_convert_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert), __func__); @@ -104,7 +102,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( source_name, result_domain, result_type); if (!source_attribute) { params.error_message_add(NodeWarningType::Error, @@ -118,7 +116,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArray_GSpan source_span{*source_attribute}; + GVArray_GSpan source_span{source_attribute}; GMutableSpan result_span = result_attribute.as_span(); BLI_assert(source_span.size() == result_span.size()); @@ -130,7 +128,7 @@ static void attribute_convert_calc(GeometryComponent &component, result_attribute.save(); } -static void geo_node_attribute_convert_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -175,18 +173,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc void register_node_type_geo_attribute_convert() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_convert_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout; - node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc index 669ac21436f..8c8b43825ec 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc { -static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -34,9 +34,7 @@ static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_curve_map_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); bNode *node = (bNode *)ptr->data; @@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout, } } -static void geo_node_attribute_curve_map_free_storage(bNode *node) +static void node_free_storage(bNode *node) { if (node->storage) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node) } } -static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree), - bNode *dest_node, - const bNode *src_node) +static void node_copy_storage(bNodeTree *UNUSED(dest_ntree), + bNode *dest_node, + const bNode *src_node) { dest_node->storage = MEM_dupallocN(src_node->storage); NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage; @@ -75,7 +73,7 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb); } -static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap), __func__); @@ -87,7 +85,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *UNUSED(ntree), bNode *node) { /* Set the active curve when data type is changed. */ NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -136,10 +134,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (result_type) { case CD_PROP_FLOAT: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, float(0.0f)); MutableSpan<float> results = attribute_result.as_span<float>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]); } @@ -148,10 +146,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_FLOAT3: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float3> attribute_in = component.attribute_get_for_read<float3>( + VArray<float3> attribute_in = component.attribute_get_for_read<float3>( input_name, result_domain, float3(0.0f)); MutableSpan<float3> results = attribute_result.as_span<float3>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]); } @@ -160,11 +158,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_COLOR: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb; - GVArray_Typed<ColorGeometry4f> attribute_in = - component.attribute_get_for_read<ColorGeometry4f>( - input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + VArray<ColorGeometry4f> attribute_in = component.attribute_get_for_read<ColorGeometry4f>( + input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]); } @@ -180,7 +177,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &bnode = params.node(); NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage; @@ -204,23 +201,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc void register_node_type_geo_attribute_curve_map() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_storage(&ntype, - "NodeAttributeCurveMap", - blender::nodes::geo_node_attribute_curve_map_free_storage, - blender::nodes::geo_node_attribute_curve_map_copy_storage); - ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout; + node_type_storage( + &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc index 5cb49dd83d0..e84c35eeada 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_fill_cc { -static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).is_attribute_name(); @@ -33,7 +33,7 @@ static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C) uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_AUTO; } -static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *socket_value_float = socket_value_vector->next; @@ -57,11 +57,11 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); } static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name) @@ -127,7 +127,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams attribute.save(); } -static void geo_node_attribute_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc void register_node_type_geo_attribute_fill() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout; - ntype.declare = blender::nodes::geo_node_attribute_fill_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc index 978c75187fe..8ebcf34ad0b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_map_range_cc { -static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -49,7 +49,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); } -static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), __func__); @@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; @@ -78,23 +78,26 @@ static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); - nodeSetSocketAvailability(sock_clamp, + nodeSetSocketAvailability(ntree, + sock_clamp, node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR || node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_steps_float, + nodeSetSocketAvailability(ntree, sock_from_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_from_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, + sock_steps_float, data_type == CD_PROP_FLOAT && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_steps_vector, + nodeSetSocketAvailability(ntree, sock_from_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_from_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, + sock_steps_vector, data_type == CD_PROP_FLOAT3 && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); } @@ -362,7 +365,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP const AttributeDomain domain = get_result_domain(component, input_name, result_name); - GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); + GVArray attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); if (!attribute_input) { params.error_message_add(NodeWarningType::Error, @@ -381,12 +384,12 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP switch (data_type) { case CD_PROP_FLOAT: { - map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params); + map_range_float(attribute_input.typed<float>(), attribute_result.as_span<float>(), params); break; } case CD_PROP_FLOAT3: { map_range_float3( - attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params); + attribute_input.typed<float3>(), attribute_result.as_span<float3>(), params); break; } default: @@ -396,7 +399,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -413,20 +416,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc void register_node_type_geo_attribute_map_range() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec; - node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_map_range_declare; - ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::fn_attribute_map_range_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc index 55d35f87cda..11f06adcf50 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_math_cc { -static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation) return false; } -static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; @@ -119,7 +119,7 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__); @@ -141,19 +141,21 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab BLI_strncpy(label, IFACE_(name), maxlen); } -static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage.input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage.input_type_c, @@ -250,7 +252,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP return; } - GVArray_Typed<float> attribute_a = params.get_input_attribute<float>( + VArray<float> attribute_a = params.get_input_attribute<float>( "A", component, result_domain, 0.0f); MutableSpan<float> result_span = attribute_result.as_span(); @@ -258,10 +260,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP /* Note that passing the data with `get_internal_span<float>()` works * because the attributes were accessed with #CD_PROP_FLOAT. */ if (operation_use_input_b(operation)) { - GVArray_Typed<float> attribute_b = params.get_input_attribute<float>( + VArray<float> attribute_b = params.get_input_attribute<float>( "B", component, result_domain, 0.0f); if (operation_use_input_c(operation)) { - GVArray_Typed<float> attribute_c = params.get_input_attribute<float>( + VArray<float> attribute_c = params.get_input_attribute<float>( "C", component, result_domain, 0.0f); do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation); } @@ -276,7 +278,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -295,20 +297,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_math_cc void register_node_type_geo_attribute_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_label(&ntype, file_ns::geo_node_math_label); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc index b4205bc91b7..e99c75dbd68 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_mix_cc { -static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -48,7 +48,7 @@ static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -59,7 +59,7 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix), "attribute mix node"); @@ -70,15 +70,15 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_attribute_mix_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); } static void do_mix_operation_float(const int blend_mode, @@ -144,25 +144,28 @@ static void do_mix_operation(const CustomDataType result_type, GVMutableArray &attribute_result) { if (result_type == CD_PROP_FLOAT) { + VMutableArray<float> result = attribute_result.typed<float>(); do_mix_operation_float(blend_mode, attribute_factor, attribute_a.typed<float>(), attribute_b.typed<float>(), - attribute_result.typed<float>()); + result); } else if (result_type == CD_PROP_FLOAT3) { + VMutableArray<float3> result = attribute_result.typed<float3>(); do_mix_operation_float3(blend_mode, attribute_factor, attribute_a.typed<float3>(), attribute_b.typed<float3>(), - attribute_result.typed<float3>()); + result); } else if (result_type == CD_PROP_COLOR) { + VMutableArray<ColorGeometry4f> result = attribute_result.typed<ColorGeometry4f>(); do_mix_operation_color4f(blend_mode, attribute_factor, attribute_a.typed<ColorGeometry4f>(), attribute_b.typed<ColorGeometry4f>(), - attribute_result.typed<ColorGeometry4f>()); + result); } } @@ -203,23 +206,23 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa return; } - GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>( + VArray<float> attribute_factor = params.get_input_attribute<float>( "Factor", component, result_domain, 0.5f); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, result_type, nullptr); do_mix_operation(result_type, node_storage->blend_type, attribute_factor, - *attribute_a, - *attribute_b, - *attribute_result); + attribute_a, + attribute_b, + attribute_result.varray()); attribute_result.save(); } -static void geo_node_attribute_mix_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -238,19 +241,21 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc void register_node_type_geo_attribute_mix() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update); - ntype.declare = blender::nodes::geo_node_mix_attribute_declare; - ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc index 9e3a7984c53..9090503924e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_proximity_cc { -static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target")); @@ -37,14 +37,12 @@ static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_proximity_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE); } -static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN( sizeof(NodeGeometryAttributeProximity), __func__); @@ -153,7 +151,7 @@ static void attribute_calc_proximity(GeometryComponent &component, if (!position_attribute || (!distance_attribute && !location_attribute)) { return; } - GVArray_Typed<float3> positions{*position_attribute.varray}; + VArray<float3> positions = position_attribute.varray.typed<float3>(); const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)params.node().storage; @@ -203,7 +201,7 @@ static void attribute_calc_proximity(GeometryComponent &component, } } -static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); @@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc void register_node_type_geo_legacy_attribute_proximity() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc index 2901472d661..8fb05d031a6 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc @@ -25,7 +25,41 @@ namespace blender::nodes { -static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b) +Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, + const AttributeDomain domain) +{ + const int domain_size = component.attribute_domain_size(domain); + + /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ + GVArray hash_attribute = component.attribute_try_get_for_read("id", domain); + Array<uint32_t> hashes(domain_size); + if (hash_attribute) { + BLI_assert(hashes.size() == hash_attribute.size()); + const CPPType &cpp_type = hash_attribute.type(); + BLI_assert(cpp_type.is_hashable()); + GVArray_GSpan items{hash_attribute}; + threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { + for (const int i : range) { + hashes[i] = cpp_type.hash(items[i]); + } + }); + } + else { + /* If there is no "id" attribute for per-point variation, just create it here. */ + RandomNumberGenerator rng(0); + for (const int i : hashes.index_range()) { + hashes[i] = rng.get_uint32(); + } + } + + return hashes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_attribute_randomize_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -39,15 +73,13 @@ static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder & b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_legacy_attribute_random_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN( sizeof(NodeAttributeRandomize), __func__); @@ -57,7 +89,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN node->storage = data; } -static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -68,12 +100,12 @@ static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); } template<typename T> @@ -174,36 +206,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span, }); } -Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, - const AttributeDomain domain) -{ - const int domain_size = component.attribute_domain_size(domain); - - /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ - GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain); - Array<uint32_t> hashes(domain_size); - if (hash_attribute) { - BLI_assert(hashes.size() == hash_attribute->size()); - const CPPType &cpp_type = hash_attribute->type(); - BLI_assert(cpp_type.is_hashable()); - GVArray_GSpan items{*hash_attribute}; - threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - hashes[i] = cpp_type.hash(items[i]); - } - }); - } - else { - /* If there is no "id" attribute for per-point variation, just create it here. */ - RandomNumberGenerator rng(0); - for (const int i : hashes.index_range()) { - hashes[i] = rng.get_uint32(); - } - } - - return hashes; -} - static AttributeDomain get_result_domain(const GeometryComponent &component, const GeoNodeExecParams ¶ms, const StringRef name) @@ -280,7 +282,7 @@ static void randomize_attribute_on_component(GeometryComponent &component, attribute.save(); } -static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const std::string attribute_name = params.get_input<std::string>("Attribute"); @@ -324,20 +326,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc void register_node_type_geo_legacy_attribute_randomize() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init); - node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); - ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc index 19d6ced6eb6..70fa0af956f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc @@ -28,9 +28,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc { -static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Texture>(N_("Texture")).hide_label(); @@ -82,7 +82,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec return; } - GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>( + VArray<float3> mapping_attribute = component.attribute_get_for_read<float3>( mapping_name, result_domain, {0, 0, 0}); MutableSpan<ColorGeometry4f> colors = attribute_out.as_span(); @@ -100,7 +100,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec attribute_out.save(); } -static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -119,10 +119,12 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc void register_node_type_geo_sample_texture() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -131,7 +133,7 @@ void register_node_type_geo_sample_texture() NODE_CLASS_ATTRIBUTE, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc index 809e75e73a3..04de44446af 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc { -static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -32,16 +32,14 @@ static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_separate_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN( sizeof(NodeAttributeSeparateXYZ), __func__); @@ -49,11 +47,11 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_attribute_separate_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); } static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result) @@ -106,9 +104,9 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa const AttributeDomain result_domain = get_result_domain( component, params, result_name_x, result_name_y, result_name_z); - GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>( + VArray<float3> attribute_input = params.get_input_attribute<float3>( "Vector", component, result_domain, {0, 0, 0}); - VArray_Span<float3> input_span{*attribute_input}; + VArray_Span<float3> input_span{attribute_input}; OutputAttribute_Typed<float> attribute_result_x = component.attribute_try_get_for_output_only<float>(result_name_x, result_domain); @@ -132,7 +130,7 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa } } -static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -151,10 +149,12 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc void register_node_type_geo_attribute_separate_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -162,12 +162,12 @@ void register_node_type_geo_attribute_separate_xyz() "Attribute Separate XYZ", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc index 3a9cd52661a..afdadee97c7 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -29,9 +29,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_transfer_cc { -static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Source Geometry")); @@ -40,9 +40,7 @@ static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_transfer_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +48,7 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout, uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE); } -static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN( sizeof(NodeGeometryAttributeTransfer), __func__); @@ -407,13 +405,13 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) { /* Point-cloud point is closer. */ const int index = pointcloud_indices[i]; - pointcloud_src_attribute.varray->get(index, buffer); + pointcloud_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } else { /* Mesh element is closer. */ const int index = mesh_indices[i]; - mesh_src_attribute.varray->get(index, buffer); + mesh_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -424,7 +422,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, src_name, data_type); for (const int i : IndexRange(tot_samples)) { const int index = pointcloud_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -434,7 +432,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, data_type); for (const int i : IndexRange(tot_samples)) { const int index = mesh_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -460,7 +458,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, const AttributeDomain dst_domain = (input_domain == ATTR_DOMAIN_AUTO) ? auto_domain : input_domain; - GVArray_Typed<float3> dst_positions = dst_component.attribute_get_for_read<float3>( + VArray<float3> dst_positions = dst_component.attribute_get_for_read<float3>( "position", dst_domain, {0, 0, 0}); switch (mapping) { @@ -477,7 +475,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, } } -static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry"); @@ -510,21 +508,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) params.set_output("Geometry", dst_geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc void register_node_type_geo_legacy_attribute_transfer() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeTransfer", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_transfer_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc index 4c351846243..1bd1712f22d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc { -static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation) NODE_VECTOR_MATH_MULTIPLY_ADD); } -static void geo_node_attribute_vector_math_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage; @@ -103,7 +101,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op return CD_PROP_FLOAT3; } -static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN( sizeof(NodeAttributeVectorMath), __func__); @@ -166,19 +164,21 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree), BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name)); } -static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage; const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage->input_type_c, @@ -187,7 +187,7 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -218,7 +218,7 @@ static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float3> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -251,7 +251,7 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -283,7 +283,7 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -313,7 +313,7 @@ static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -342,7 +342,7 @@ static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -369,7 +369,7 @@ static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -437,13 +437,13 @@ static void attribute_vector_math_calc(GeometryComponent &component, const AttributeDomain result_domain = get_result_domain( component, params, operation, result_name); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, read_type_a, nullptr); if (!attribute_a) { return; } - GVArrayPtr attribute_b; - GVArrayPtr attribute_c; + GVArray attribute_b; + GVArray attribute_c; if (use_input_b) { attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr); if (!attribute_b) { @@ -476,26 +476,26 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_MODULO: case NODE_VECTOR_MATH_MINIMUM: case NODE_VECTOR_MATH_MAXIMUM: - do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_DOT_PRODUCT: case NODE_VECTOR_MATH_DISTANCE: - do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float>(), + do_math_operation_fl3_fl3_to_fl(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_LENGTH: do_math_operation_fl3_to_fl( - attribute_a->typed<float3>(), attribute_result->typed<float>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_SCALE: - do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_NORMALIZE: @@ -507,29 +507,29 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_COSINE: case NODE_VECTOR_MATH_TANGENT: do_math_operation_fl3_to_fl3( - attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_WRAP: case NODE_VECTOR_MATH_FACEFORWARD: case NODE_VECTOR_MATH_MULTIPLY_ADD: - do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_REFRACT: - do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; } attribute_result.save(); } -static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -549,10 +549,12 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc void register_node_type_geo_attribute_vector_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -560,12 +562,12 @@ void register_node_type_geo_attribute_vector_math() "Attribute Vector Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_vector_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_label(&ntype, file_ns::geo_node_vector_math_label); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc index 9ab8ec25fb6..309518e58ce 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc @@ -21,9 +21,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc { -static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -42,9 +42,7 @@ static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage; @@ -70,27 +68,30 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, } } -static void geo_node_attribute_vector_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage; const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode) node_storage->mode; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); update_attribute_input_socket_availabilities( - *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); + *ntree, *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS)); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -109,7 +110,7 @@ static float3 vector_rotate_around_axis(const float3 vector, return result + center; } -static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN( sizeof(NodeAttributeVectorRotate), __func__); @@ -220,12 +221,12 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon const AttributeDomain result_domain = get_result_domain(component, params, result_name); const bool invert = params.get_input<bool>("Invert"); - GVArrayPtr attribute_vector = params.get_input_attribute( + GVArray attribute_vector = params.get_input_attribute( "Vector", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_vector) { return; } - GVArrayPtr attribute_center = params.get_input_attribute( + GVArray attribute_center = params.get_input_attribute( "Center", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_center) { return; @@ -238,21 +239,21 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) { - GVArrayPtr attribute_rotation = params.get_input_attribute( + GVArray attribute_rotation = params.get_input_attribute( "Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_rotation) { return; } - do_vector_rotate_euler(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_rotation->typed<float3>(), + do_vector_rotate_euler(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_rotation.typed<float3>(), attribute_result.as_span<float3>(), invert); attribute_result.save(); return; } - GVArrayPtr attribute_angle = params.get_input_attribute( + GVArray attribute_angle = params.get_input_attribute( "Angle", component, result_domain, CD_PROP_FLOAT, nullptr); if (!attribute_angle) { return; @@ -260,40 +261,40 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (mode) { case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: { - GVArrayPtr attribute_axis = params.get_input_attribute( + GVArray attribute_axis = params.get_input_attribute( "Axis", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_axis) { return; } - do_vector_rotate_around_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_axis->typed<float3>(), - attribute_angle->typed<float>(), + do_vector_rotate_around_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_axis.typed<float3>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); } break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(1.0f, 0.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 1.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 0.0f, 1.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); @@ -306,7 +307,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -325,10 +326,12 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc void register_node_type_geo_attribute_vector_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -336,13 +339,13 @@ void register_node_type_geo_attribute_vector_rotate() "Attribute Vector Rotate", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size(&ntype, 165, 100, 600); node_type_storage( &ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout; - ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index 8b81008ff34..184f39ba094 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_endpoints_cc { -static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Start Points")); @@ -61,7 +61,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( @@ -70,7 +70,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, /* Only copy the attributes of splines in the offsets. */ for (const int i : offsets.index_range()) { - spline_attribute->get(offsets[i], result[i]); + spline_attribute.get(offsets[i], result[i]); } result_attribute.save(); @@ -130,7 +130,7 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]); + spline_span.type().copy_assign(spline_span[0], point_span[i]); } for (const auto item : end_data.point_attributes.items()) { @@ -139,13 +139,13 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]); + spline_span.type().copy_assign(spline_span[spline.size() - 1], point_span[i]); } } }); } -static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -206,16 +206,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) params.set_output("End Points", std::move(end_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc void register_node_type_geo_legacy_curve_endpoints() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoints_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index ba76fafe3e6..cfc67e13a8d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -20,16 +20,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); geometry_set = bke::geometry_set_realize_instances(geometry_set); @@ -44,7 +44,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { @@ -58,14 +58,16 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc void register_node_type_geo_legacy_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index 40d827ae141..a839c53c855 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc @@ -23,24 +23,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc { -static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -94,7 +92,7 @@ static void select_curve_by_handle_type(const CurveEval &curve, }); } -static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSelectHandles *storage = (const NodeGeometryCurveSelectHandles *)params.node().storage; @@ -121,10 +119,12 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc void register_node_type_geo_legacy_select_by_handle_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,14 +132,14 @@ void register_node_type_geo_legacy_select_by_handle_type() "Select by Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index 4bac9cb976e..fbc56adf44c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -21,24 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_set_handles_cc { -static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b) +static void node_decalre(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSetHandles *node_storage = (NodeGeometryCurveSetHandles *)params.node().storage; @@ -84,7 +82,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_POINT, true); const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type); @@ -124,21 +122,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc void register_node_type_geo_legacy_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_decalre; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index df53c96e6ca..7c76f97c97f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -23,23 +23,21 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_spline_type_cc { -static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,7 +236,7 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType *storage = (const NodeGeometryCurveSplineType *)params.node().storage; @@ -255,7 +253,7 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) const CurveEval &curve = *curve_component->get_for_read(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component->attribute_get_for_read( + VArray<bool> selection = curve_component->attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); @@ -282,21 +280,23 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc void register_node_type_geo_legacy_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index f9b0a9d128e..b7cddb927f8 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -25,13 +25,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_legacy_curve_subdivide_cc { -namespace blender::nodes { - -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Cuts")); @@ -39,14 +35,14 @@ static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE); } -static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN( sizeof(NodeGeometryCurveSubdivide), __func__); @@ -55,12 +51,12 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); } static Array<int> get_subdivided_offsets(const Spline &spline, @@ -351,7 +347,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -363,34 +359,35 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) } const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>(); - GVArray_Typed<int> cuts = params.get_input_attribute<int>( - "Cuts", component, ATTR_DOMAIN_POINT, 0); - if (cuts->is_single() && cuts->get_internal_single() < 1) { + VArray<int> cuts = params.get_input_attribute<int>("Cuts", component, ATTR_DOMAIN_POINT, 0); + if (cuts.is_single() && cuts.get_internal_single() < 1) { params.set_output("Geometry", geometry_set); return; } - std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts); + std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts); params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc void register_node_type_geo_legacy_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage(&ntype, "NodeGeometryCurveSubdivide", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index c171d485a6a..a64443261ae 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -28,7 +28,59 @@ namespace blender::nodes { -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id, + const CustomDataType data_type) +{ + points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); + WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); + BLI_assert(attribute); + return attribute.varray.get_internal_span(); +} + +template<typename T> +static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id) +{ + GMutableSpan attribute = create_attribute_and_retrieve_span( + points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); + return attribute.typed<T>(); +} + +CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, + const CurveEval &curve) +{ + CurveToPointsResults attributes; + + attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); + + attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); + attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); + attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); + + /* Because of the invariants of the curve component, we use the attributes of the + * first spline as a representative for the attribute meta data all splines. */ + curve.splines().first()->attributes.foreach_attribute( + [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + attributes.point_attributes.add_new( + attribute_id, + create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); + return true; + }, + ATTR_DOMAIN_POINT); + + attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); + attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); + attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); + + return attributes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_curve_to_points_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); @@ -36,12 +88,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -50,7 +102,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -58,8 +110,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } /** @@ -114,54 +166,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, return {0}; } -static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id, - const CustomDataType data_type) -{ - points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); - WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); - BLI_assert(attribute); - return attribute.varray->get_internal_span(); -} - -template<typename T> -static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id) -{ - GMutableSpan attribute = create_attribute_and_retrieve_span( - points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); - return attribute.typed<T>(); -} - -CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, - const CurveEval &curve) -{ - CurveToPointsResults attributes; - - attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); - - attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); - attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); - attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); - - /* Because of the invariants of the curve component, we use the attributes of the - * first spline as a representative for the attribute meta data all splines. */ - curve.splines().first()->attributes.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - attributes.point_attributes.add_new( - attribute_id, - create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); - return true; - }, - ATTR_DOMAIN_POINT); - - attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); - attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); - attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); - - return attributes; -} - /** * TODO: For non-poly splines, this has double copies that could be avoided as part * of a general look at optimizing uses of #Spline::interpolate_to_evaluated. @@ -177,8 +181,8 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); - spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.tilts()).materialize(data.tilts.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -188,7 +192,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, GSpan spline_span = *spline.attributes.get_for_read(attribute_id); spline.interpolate_to_evaluated(spline_span) - ->materialize(point_span.slice(offset, size).data()); + .materialize(point_span.slice(offset, size).data()); } data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents()); @@ -230,7 +234,7 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, point_span.slice(offset, size)); } @@ -263,20 +267,20 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); - const CPPType &type = spline_attribute->type(); + const CPPType &type = spline_attribute.type(); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type); GMutableSpan result = result_attribute.as_span(); - for (const int i : IndexRange(spline_attribute->size())) { + for (const int i : spline_attribute.index_range()) { const int offset = offsets[i]; const int size = offsets[i + 1] - offsets[i]; if (size != 0) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - spline_attribute->get(i, buffer); + spline_attribute.get(i, buffer); type.fill_assign_n(buffer, result[offset], size); } } @@ -286,7 +290,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, }); } -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -340,21 +344,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc void register_node_type_geo_legacy_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index 1d76a0532a1..0ae5766a27d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -29,23 +29,23 @@ using blender::bke::CustomDataAttributes; /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); - -namespace blender::nodes { - -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); + +namespace blender::nodes::node_geo_legacy_delete_geometry_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); @@ -137,7 +137,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, Vector<int64_t> copied_splines; if (input_curve.attributes.get_for_read(name)) { - GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); for (const int i : input_splines.index_range()) { if (selection[i] == invert) { output_curve->add_spline(input_splines[i]->copy()); @@ -151,7 +151,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, for (const int i : input_splines.index_range()) { const Spline &spline = *input_splines[i]; - GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = spline.attributes.get_for_read<bool>(name, false); indices_to_copy.clear(); for (const int i_point : IndexRange(spline.size())) { @@ -202,7 +202,7 @@ static void delete_point_cloud_selection(const PointCloudComponent &in_component const StringRef selection_name, const bool invert) { - const GVArray_Typed<bool> selection_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> selection_attribute = in_component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> selection{selection_attribute}; @@ -590,7 +590,7 @@ static void delete_mesh_selection(MeshComponent &component, const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name); /* This already checks if the attribute exists, and displays a warning in that case. */ - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, selection_domain, false); /* Check if there is anything to delete. */ @@ -627,7 +627,7 @@ static void delete_mesh_selection(MeshComponent &component, component.replace(mesh_out); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); geometry_set = bke::geometry_set_realize_instances(geometry_set); @@ -662,16 +662,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(out_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc void register_node_type_geo_legacy_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc index 8f2bf05d2b4..0a510105f5f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc @@ -22,9 +22,9 @@ extern "C" { Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd); } -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true); @@ -37,7 +37,7 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_edge_split_cc void register_node_type_geo_legacy_edge_split() { + namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc index 333a17aa4e9..00833e81c29 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_material_assign_cc { -static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(true); @@ -59,7 +59,7 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, } } -static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string mask_name = params.extract_input<std::string>("Selection"); @@ -72,7 +72,7 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); Mesh *mesh = mesh_component.get_for_write(); if (mesh != nullptr) { - GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>( + VArray<bool> face_mask = mesh_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_FACE, true); assign_material_to_faces(*mesh, face_mask, material); } @@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_material_assign_cc void register_node_type_geo_legacy_material_assign() { + namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index 9167096fd3d..e384124d3e1 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -18,16 +18,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -44,7 +44,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + selection_name + "\""); } - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_EDGE, true); Vector<int64_t> selected_edge_indices; @@ -65,15 +65,17 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc void register_node_type_geo_legacy_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc index 210757f986d..d62f3536680 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc @@ -36,11 +36,11 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_legacy_point_distribute_cc { -namespace blender::nodes { +using blender::bke::GeometryInstanceGroup; -static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE); @@ -54,18 +54,17 @@ static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_distribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); + nodeSetSocketAvailability( + ntree, sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); } /** @@ -106,9 +105,9 @@ static void sample_mesh_surface(const Mesh &mesh, float looptri_density_factor = 1.0f; if (density_factors != nullptr) { - const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop)); - const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop)); - const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop)); + const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]); + const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]); + const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]); looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f; } const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); @@ -315,7 +314,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( } const AttributeDomain source_domain = attribute_info->domain; - GVArrayPtr source_attribute = source_component.attribute_get_for_read( + GVArray source_attribute = source_component.attribute_get_for_read( attribute_id, source_domain, output_data_type, nullptr); if (!source_attribute) { i_instance += set_group.transforms.size(); @@ -329,7 +328,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( GMutableSpan instance_span = out_span.slice(offset, bary_coords.size()); interpolate_attribute( - mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span); + mesh, bary_coords, looptri_indices, source_domain, source_attribute, instance_span); i_instance++; } @@ -337,7 +336,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> source_span{*source_attribute}; + VArray_Span source_span{source_attribute.typed<T>()}; }); } @@ -445,7 +444,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); const Mesh &mesh = *component.get_for_read(); for (const float4x4 &transform : set_group.transforms) { @@ -455,7 +454,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, sample_mesh_surface(mesh, transform, density, - &*density_factors, + &density_factors, seed, positions, bary_coords, @@ -514,7 +513,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); const Mesh &mesh = *component.get_for_read(); - const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + const VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { @@ -540,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group } } -static void geo_node_point_distribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -654,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_distribute_cc void register_node_type_geo_point_distribute() { + namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_update); - ntype.declare = blender::nodes::geo_node_point_distribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout; + node_type_update(&ntype, file_ns::node_point_distribute_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc index ffb2a0dd7ac..be8294cda90 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_instance_cc { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Object>(N_("Object")).hide_label(); @@ -36,7 +36,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE); if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { @@ -44,7 +44,7 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN( sizeof(NodeGeometryPointInstance), __func__); @@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *collection_socket = object_socket->next; @@ -65,12 +65,15 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) const bool use_whole_collection = (node_storage->flag & GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0; - nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); - nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); - nodeSetSocketAvailability(instance_geometry_socket, - type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); nodeSetSocketAvailability( - seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection); + ntree, collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); + nodeSetSocketAvailability( + ntree, instance_geometry_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, + seed_socket, + type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && + !use_whole_collection); } static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams ¶ms) @@ -171,13 +174,12 @@ static void add_instances_from_component(InstancesComponent &instances, const int domain_size = src_geometry.attribute_domain_size(domain); - GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>( + VArray<float3> positions = src_geometry.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); - GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>( + VArray<float3> rotations = src_geometry.attribute_get_for_read<float3>( "rotation", domain, {0, 0, 0}); - GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>( - "scale", domain, {1, 1, 1}); - GVArray_Typed<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); + VArray<float3> scales = src_geometry.attribute_get_for_read<float3>("scale", domain, {1, 1, 1}); + VArray<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); /* The initial size of the component might be non-zero if there are two component types. */ const int start_len = instances.instances_amount(); @@ -213,7 +215,7 @@ static void add_instances_from_component(InstancesComponent &instances, } } -static void geo_node_point_instance_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -253,20 +255,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_instance_cc void register_node_type_geo_point_instance() { + namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_instance_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout; - node_type_update(&ntype, blender::nodes::geo_node_point_instance_update); - ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc index 54d36dab98d..7cdd03baa02 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_rotate_cc { -static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Axis")); @@ -37,7 +37,7 @@ static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage; @@ -57,7 +57,7 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), } } -static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN( sizeof(NodeGeometryRotatePoints), __func__); @@ -71,20 +71,23 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = node_storage; } -static void geo_node_point_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -169,9 +172,9 @@ static void point_rotate_on_component(GeometryComponent &component, const int domain_size = rotations.size(); if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) { - GVArray_Typed<float3> axis = params.get_input_attribute<float3>( + VArray<float3> axis = params.get_input_attribute<float3>( "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1}); - GVArray_Typed<float> angles = params.get_input_attribute<float>( + VArray<float> angles = params.get_input_attribute<float>( "Angle", component, ATTR_DOMAIN_POINT, 0); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -182,7 +185,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } else { - GVArray_Typed<float3> eulers = params.get_input_attribute<float3>( + VArray<float3> eulers = params.get_input_attribute<float3>( "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -196,7 +199,7 @@ static void point_rotate_on_component(GeometryComponent &component, rotation_attribute.save(); } -static void geo_node_point_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -215,19 +218,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_rotate_cc void register_node_type_geo_point_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_rotate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc index 934442ee8a3..4a6f19b8ed2 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_scale_cc { -static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -34,14 +34,14 @@ static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN( sizeof(NodeGeometryPointScale), __func__); @@ -50,12 +50,12 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_scale_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); } static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) @@ -78,7 +78,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT : CD_PROP_FLOAT3; - GVArrayPtr attribute = params.get_input_attribute( + GVArray attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr); if (!attribute) { return; @@ -86,13 +86,13 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co MutableSpan<float3> scale_span = scale_attribute.as_span(); if (data_type == CD_PROP_FLOAT) { - GVArray_Typed<float> factors{*attribute}; + VArray<float> factors = attribute.typed<float>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } } else if (data_type == CD_PROP_FLOAT3) { - GVArray_Typed<float3> factors{*attribute}; + VArray<float3> factors = attribute.typed<float3>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } @@ -101,7 +101,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co scale_attribute.save(); } -static void geo_node_point_scale_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -120,20 +120,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_scale_cc void register_node_type_geo_point_scale() { + namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_scale_declare; - node_type_init(&ntype, blender::nodes::geo_node_point_scale_init); - node_type_update(&ntype, blender::nodes::geo_node_point_scale_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc index accdaf78439..5d18abbc828 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc @@ -25,14 +25,6 @@ namespace blender::nodes { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::String>(N_("Mask")); - b.add_output<decl::Geometry>(N_("Geometry 1")); - b.add_output<decl::Geometry>(N_("Geometry 2")); -} - template<typename T> static void copy_data_based_on_mask(Span<T> data, Span<bool> masks, @@ -55,7 +47,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, { for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) { ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); /* Only copy point attributes. Theoretically this could interpolate attributes on other * domains to the point domain, but that would conflict with attributes that are built-in @@ -69,7 +61,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data_based_on_mask(span, masks, invert, out_span); }); @@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, } } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_point_separate_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::String>(N_("Mask")); + b.add_output<decl::Geometry>(N_("Geometry 1")); + b.add_output<decl::Geometry>(N_("Geometry 2")); +} + static void create_component_points(GeometryComponent &component, const int total) { switch (component.type()) { @@ -103,7 +107,7 @@ static void separate_points_from_component(const GeometryComponent &in_component return; } - const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> mask_attribute = in_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> masks{mask_attribute}; @@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in, return set_out; } -static void geo_node_point_separate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { bool wait_for_inputs = false; wait_for_inputs |= params.lazy_require_input("Geometry"); @@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_separate_cc void register_node_type_geo_point_separate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc index 34f7641995f..4e18c650199 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_translate_cc { -static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Translation")); @@ -29,7 +29,7 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -43,17 +43,17 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co if (!position_attribute) { return; } - GVArray_Typed<float3> attribute = params.get_input_attribute<float3>( + VArray<float3> attribute = params.get_input_attribute<float3>( "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); - for (const int i : IndexRange(attribute.size())) { + for (const int i : attribute.index_range()) { position_attribute->set(i, position_attribute->get(i) + attribute[i]); } position_attribute.save(); } -static void geo_node_point_translate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -72,7 +72,7 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN( sizeof(NodeGeometryPointTranslate), __func__); @@ -81,30 +81,32 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_translate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_translate_cc void register_node_type_geo_point_translate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_translate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_translate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryPointTranslate", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_translate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc index cf7f466c2a6..2c34d0d781e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc @@ -28,9 +28,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); @@ -41,9 +41,7 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -51,7 +49,7 @@ static void geo_node_points_to_volume_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -65,19 +63,22 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node STRNCPY(radius_attribute_socket_value->value, "radius"); } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); - nodeSetSocketAvailability( - voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + nodeSetSocketAvailability(ntree, + voxel_size_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); update_attribute_input_socket_availabilities( - *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); + *ntree, *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); } #ifdef WITH_OPENVDB @@ -172,12 +173,12 @@ static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - GVArray_Typed<float> radii = params.get_input_attribute<float>( + VArray<float> radii = params.get_input_attribute<float>( "Radius", component, ATTR_DOMAIN_POINT, 0.0f); - for (const int i : IndexRange(positions.size())) { + for (const int i : positions.index_range()) { r_positions.append(positions[i]); r_radii.append(radii[i]); } @@ -241,7 +242,7 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_ } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -256,10 +257,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc void register_node_type_geo_legacy_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -269,10 +272,10 @@ void register_node_type_geo_legacy_points_to_volume() node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); - node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); - ntype.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc index e6a81fc9627..83081933c64 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_raycast_cc { -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target Geometry")); @@ -47,7 +47,7 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -56,7 +56,7 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -65,15 +65,19 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Ray Direction", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction); update_attribute_input_socket_availabilities( - *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); + *ntree, + *node, + "Ray Length", + (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); } static void raycast_to_mesh(const Mesh &mesh, @@ -197,11 +201,11 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, (GeometryNodeRaycastMapMode)storage.mapping); const AttributeDomain result_domain = ATTR_DOMAIN_POINT; - GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>( + VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>( "position", result_domain, {0, 0, 0}); - GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>( + VArray<float3> ray_directions = params.get_input_attribute<float3>( "Ray Direction", dst_component, result_domain, {0, 0, 0}); - GVArray_Typed<float> ray_lengths = params.get_input_attribute<float>( + VArray<float> ray_lengths = params.get_input_attribute<float>( "Ray Length", dst_component, result_domain, 0); OutputAttribute_Typed<bool> hit_attribute = @@ -218,10 +222,10 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, Array<int> hit_indices; Array<float3> hit_positions_internal; if (!hit_attribute_names.is_empty()) { - hit_indices.reinitialize(ray_origins->size()); + hit_indices.reinitialize(ray_origins.size()); if (!hit_position_attribute) { - hit_positions_internal.reinitialize(ray_origins->size()); + hit_positions_internal.reinitialize(ray_origins.size()); } } const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>(); @@ -268,7 +272,7 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry"); @@ -303,20 +307,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_raycast_cc void register_node_type_geo_legacy_raycast() { + namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc index a8d6f33a5fd..0119570b199 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_select_by_material_cc { -static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(); @@ -54,7 +54,7 @@ static void select_mesh_by_material(const Mesh &mesh, }); } -static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string selection_name = params.extract_input<std::string>("Selection"); @@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_select_by_material_cc void register_node_type_geo_legacy_select_by_material() { + namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc index 295cd05fd01..dd9c26f3790 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc @@ -23,9 +23,9 @@ #include "UI_resources.h" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -33,9 +33,7 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { #ifdef WITH_OPENSUBDIV uiLayoutSetPropSep(layout, true); @@ -47,7 +45,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout, #endif } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -56,7 +54,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -126,18 +124,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc void register_node_type_geo_legacy_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc index 39af5bf1fd2..acff0be7126 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc @@ -35,9 +35,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Density")); @@ -48,14 +48,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -68,15 +68,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } @@ -138,7 +140,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in, #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -153,21 +155,23 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc void register_node_type_geo_legacy_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 5cc8f1476f8..7229fda7a5c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_capture_cc { -static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Vector>(N_("Value")).supports_field(); @@ -40,9 +40,7 @@ static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source(); } -static void geo_node_attribute_capture_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +48,7 @@ static void geo_node_attribute_capture_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN( sizeof(NodeGeometryAttributeCapture), __func__); @@ -60,7 +58,7 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *) node->storage; @@ -73,11 +71,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *socket_value_boolean = socket_value_color4f->next; bNodeSocket *socket_value_int32 = socket_value_boolean->next; - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next; @@ -86,11 +84,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next; bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next; - nodeSetSocketAvailability(out_socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32); } static void try_capture_field_on_geometry(GeometryComponent &component, @@ -113,7 +111,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, output_attribute.save(); } -static void geo_node_attribute_capture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -147,16 +145,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) WeakAnonymousAttributeID anonymous_id{"Attribute"}; const CPPType &type = field.cpp_type(); - static const Array<GeometryComponentType> types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - for (const GeometryComponentType type : types) { - if (geometry_set.has(type)) { - GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); - } + /* Run on the instances component separately to only affect the top level of instances. */ + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry_set.has_instances()) { + GeometryComponent &component = geometry_set.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } - }); + } + else { + static const Array<GeometryComponentType> types = { + GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : types) { + if (geometry_set.has(type)) { + GeometryComponent &component = geometry_set.get_component_for_write(type); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + } + } + }); + } GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>( std::move(anonymous_id), type, params.attribute_producer_name())}; @@ -189,10 +198,12 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_capture_cc void register_node_type_geo_attribute_capture() { + namespace file_ns = blender::nodes::node_geo_attribute_capture_cc; + static bNodeType ntype; geo_node_type_base( @@ -201,10 +212,10 @@ void register_node_type_geo_attribute_capture() "NodeGeometryAttributeCapture", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update); - ntype.declare = blender::nodes::geo_node_attribute_capture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc index f80b8ccc971..6f26b2c756b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_remove_cc { -static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).multi_input(); @@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component, } } -static void geo_node_attribute_remove_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute"); @@ -66,15 +66,17 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_remove_cc void register_node_type_geo_attribute_remove() { + namespace file_ns = blender::nodes::node_geo_attribute_remove_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec; - ntype.declare = blender::nodes::geo_node_attribute_remove_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index 155bd8c8c28..c84031f4c6b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_statistic_cc { -static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field(); @@ -51,21 +51,19 @@ static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Variance"), "Variance_001"); } -static void geo_node_attribute_statistic_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } -static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_POINT; } -static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_float_attr = socket_geo->next; @@ -91,25 +89,25 @@ static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_float_attr, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_mean, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_median, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_sum, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_min, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_max, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_range, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_std, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_variance, data_type == CD_PROP_FLOAT); - - nodeSetSocketAvailability(socket_float3_attr, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_mean, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_median, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_sum, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_min, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_max, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_range, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_std, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_variance, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_median, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_sum, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_min, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_max, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_range, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_std, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_variance, data_type == CD_PROP_FLOAT); + + nodeSetSocketAvailability(ntree, socket_float3_attr, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_mean, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_median, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_sum, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_min, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_max, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_range, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_std, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3); } template<typename T> static T compute_sum(const Span<T> data) @@ -170,7 +168,7 @@ static void set_empty(CustomDataType data_type, GeoNodeExecParams ¶ms) } } -static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry"); @@ -360,19 +358,21 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_statistic_cc void register_node_type_geo_attribute_statistic() { + namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_statistic_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 516f07b7ad3..0947632cc09 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_boolean_cc { -static void geo_node_boolean_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh 1")) .only_realized_data() @@ -36,12 +36,12 @@ static void geo_node_boolean_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1; @@ -51,24 +51,24 @@ static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) switch (operation) { case GEO_NODE_BOOLEAN_INTERSECT: case GEO_NODE_BOOLEAN_UNION: - nodeSetSocketAvailability(geometry_1_socket, false); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, false); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh")); break; case GEO_NODE_BOOLEAN_DIFFERENCE: - nodeSetSocketAvailability(geometry_1_socket, true); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, true); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh 2")); break; } } -static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE; } -static void geo_node_boolean_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1; const bool use_self = params.get_input<bool>("Self Intersection"); @@ -119,17 +119,19 @@ static void geo_node_boolean_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_boolean_cc void register_node_type_geo_boolean() { + namespace file_ns = blender::nodes::node_geo_boolean_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_boolean_declare; - ntype.draw_buttons = blender::nodes::geo_node_boolean_layout; - ntype.updatefunc = blender::nodes::geo_node_boolean_update; - node_type_init(&ntype, blender::nodes::geo_node_boolean_init); - ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.updatefunc = file_ns::node_update; + node_type_init(&ntype, file_ns::node_init); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index e7c9715934a..da1f9a00c69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_bounding_box_cc { -static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Bounding Box")); @@ -26,7 +26,7 @@ static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Max")); } -static void geo_node_bounding_box_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -78,14 +78,16 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_bounding_box_cc void register_node_type_geo_bounding_box() { + namespace file_ns = blender::nodes::node_geo_bounding_box_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_bounding_box_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index f068e621596..1cd5f396ee5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -27,9 +27,9 @@ #include <algorithm> -namespace blender::nodes { +namespace blender::nodes::node_geo_collection_info_cc { -static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Collection>(N_("Collection")).hide_label(); b.add_input<decl::Bool>(N_("Separate Children")) @@ -38,16 +38,16 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Reset Children")) .description( N_("Reset the transforms of every child instance in the output. Only used when Separate " - "Children is enabled")); + "Children is enabled")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN( sizeof(NodeGeometryCollectionInfo), __func__); @@ -61,7 +61,7 @@ struct InstanceListEntry { float4x4 transform; }; -static void geo_node_collection_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Collection *collection = params.get_input<Collection *>("Collection"); @@ -155,20 +155,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_collection_info_cc void register_node_type_geo_collection_info() { + namespace file_ns = blender::nodes::node_geo_collection_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_collection_info_declare; - node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_node_init); node_type_storage(&ntype, "NodeGeometryCollectionInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index e2bb7e9f939..9ebbdd349de 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -31,7 +31,6 @@ void register_node_type_geo_group(void) ntype.poll = geo_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -53,7 +52,4 @@ void register_node_type_geo_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 3cf682e161c..5222e2055b1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -28,9 +28,9 @@ # include "RBI_hull_api.h" #endif -namespace blender::nodes { +namespace blender::nodes::node_geo_convex_hull_cc { -static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Convex Hull")); @@ -169,10 +169,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) span_count++; const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - total_size += varray->size(); - positions_span = varray->get_internal_span(); + total_size += varray.size(); + positions_span = varray.get_internal_span(); } if (geometry_set.has_curve()) { @@ -200,18 +200,18 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_mesh()) { const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } if (geometry_set.has_pointcloud()) { const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } @@ -235,16 +235,16 @@ static void read_positions(const GeometryComponent &component, Span<float4x4> transforms, Vector<float3> *r_coords) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); /* NOTE: could use convex hull operation here to * cut out some vertices, before accumulating, * but can also be done by the user beforehand. */ - r_coords->reserve(r_coords->size() + positions.size() * transforms.size()); + r_coords->reserve(r_coords->size() + positions->size() * transforms.size()); for (const float4x4 &transform : transforms) { - for (const int i : positions.index_range()) { + for (const int i : positions->index_range()) { const float3 position = positions[i]; const float3 transformed_position = transform * position; r_coords->append(transformed_position); @@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set) #endif /* WITH_BULLET */ -static void geo_node_convex_hull_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -316,14 +316,16 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params) #endif /* WITH_BULLET */ } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_convex_hull_cc void register_node_type_geo_convex_hull() { + namespace file_ns = blender::nodes::node_geo_convex_hull_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_convex_hull_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 42d88cdb1e7..c756185e4ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_endpoint_select_cc { -static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Start Size")) .min(0) @@ -64,9 +64,9 @@ class EndpointFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -111,9 +111,9 @@ class EndpointFieldInput final : public fn::FieldInput { } current_point += spline->size(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } - return nullptr; + return {}; }; uint64_t hash() const override @@ -131,23 +131,25 @@ class EndpointFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_endpoint_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> start_size = params.extract_input<Field<int>>("Start Size"); Field<int> end_size = params.extract_input<Field<int>>("End Size"); Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)}; params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_endpoint_select_cc void register_node_type_geo_curve_endpoint_selection() { + namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoint_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoint_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 219effadec4..4130cf99516 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -31,20 +31,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fill_cc { -static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill), __func__); @@ -147,7 +147,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu geometry_set.replace_curve(nullptr); } -static void geo_node_curve_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -160,19 +160,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fill_cc void register_node_type_geo_curve_fill() { + namespace file_ns = blender::nodes::node_geo_curve_fill_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fill_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index 27d7d22b106..ed5c9e1bc98 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -25,9 +25,9 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fillet_cc { -static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field(); @@ -41,12 +41,12 @@ static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN( sizeof(NodeGeometryCurveFillet), __func__); @@ -59,10 +59,10 @@ struct FilletParam { GeometryNodeCurveFilletMode mode; /* Number of points to be added. */ - const VArray<int> *counts; + VArray<int> counts; /* Radii for fillet arc at all vertices. */ - const VArray<float> *radii; + VArray<float> radii; /* Whether or not fillets are allowed to overlap. */ bool limit_radius; @@ -76,14 +76,14 @@ struct FilletData { Array<int> counts; }; -static void geo_node_curve_fillet_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage; const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode; bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next; - nodeSetSocketAvailability(poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); + nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); } /* Function to get the center of a fillet. */ @@ -160,7 +160,7 @@ static Array<int> calculate_counts(const FilletParam &fillet_param, Array<int> counts(size, 1); if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) { for (const int i : IndexRange(size)) { - counts[i] = (*fillet_param.counts)[spline_offset + i]; + counts[i] = fillet_param.counts[spline_offset + i]; } } if (!cyclic) { @@ -178,12 +178,12 @@ static Array<float> calculate_radii(const FilletParam &fillet_param, Array<float> radii(size, 0.0f); if (fillet_param.limit_radius) { for (const int i : IndexRange(size)) { - radii[i] = std::max((*fillet_param.radii)[spline_offset + i], 0.0f); + radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f); } } else { for (const int i : IndexRange(size)) { - radii[i] = (*fillet_param.radii)[spline_offset + i]; + radii[i] = fillet_param.radii[spline_offset + i]; } } @@ -590,13 +590,13 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, field_evaluator.evaluate(); - fillet_param.radii = &field_evaluator.get_evaluated<float>(0); - if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) { + fillet_param.radii = field_evaluator.get_evaluated<float>(0); + if (fillet_param.radii.is_single() && fillet_param.radii.get_internal_single() < 0.0f) { return; } if (mode == GEO_NODE_CURVE_FILLET_POLY) { - fillet_param.counts = &field_evaluator.get_evaluated<int>(1); + fillet_param.counts = field_evaluator.get_evaluated<int>(1); } fillet_param.limit_radius = limit_radius; @@ -607,7 +607,7 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_fillet_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -629,19 +629,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fillet_cc void register_node_type_geo_curve_fillet() { + namespace file_ns = blender::nodes::node_geo_curve_fillet_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0); - ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fillet_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update); - ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index e48c72b68d9..2a53f7a3f82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -21,22 +21,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_handle_type_selection_cc { -static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Selection")).field_source(); } -static void geo_node_curve_handle_type_selection_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_handle_type_selection_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -96,9 +94,9 @@ class HandleTypeFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -106,22 +104,22 @@ class HandleTypeFieldInput final : public fn::FieldInput { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_CURVE) { - return nullptr; + return {}; } const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_POINT) { Array<bool> selection(mask.min_array_size()); select_by_handle_type(*curve, type_, mode_, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } } - return nullptr; + return {}; }; uint64_t hash() const override @@ -140,7 +138,7 @@ class HandleTypeFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSelectHandles *storage = (const NodeGeometryCurveSelectHandles *)params.node().storage; @@ -152,22 +150,24 @@ static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params) params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc void register_node_type_geo_curve_handle_type_selection() { + namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_handle_type_selection_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc index 0d0dc0ec89c..33e9b11ec0c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc @@ -17,15 +17,15 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_length_cc { -static void geo_node_curve_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Float>(N_("Length")); } -static void geo_node_curve_length_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); if (!curve_set.has_curve()) { @@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params) params.set_output("Length", length); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_length_cc void register_node_type_geo_curve_length() { + namespace file_ns = blender::nodes::node_geo_curve_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_length_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc index 4c89aba2e6d..27b2590546b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc @@ -20,11 +20,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_parameter_cc { -static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_output<decl::Float>(N_("Factor")).field_source(); + b.add_output<decl::Float>(N_("Factor")) + .field_source() + .description( + N_("For points, the portion of the spline's total length at the control point. For " + "Splines, the factor of that spline within the entire curve")); + b.add_output<decl::Float>(N_("Length")) + .field_source() + .description( + N_("For points, the distance along the control point's spline, For splines, the " + "distance along the entire curve")); } /** @@ -32,47 +41,42 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for * each spline is the portion of the total length at the start of the spline. */ -static Array<float> curve_parameter_spline_domain(const CurveEval &curve, const IndexMask mask) +static Array<float> curve_length_spline_domain(const CurveEval &curve, + const IndexMask UNUSED(mask)) { Span<SplinePtr> splines = curve.splines(); float length = 0.0f; - Array<float> parameters(splines.size()); + Array<float> lengths(splines.size()); for (const int i : splines.index_range()) { - parameters[i] = length; + lengths[i] = length; length += splines[i]->length(); } - const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length; - mask.foreach_index([&](const int64_t i) { parameters[i] *= total_length_inverse; }); - - return parameters; + return lengths; } /** * The parameter at each control point is the factor at the corresponding evaluated point. */ -static void calculate_bezier_parameters(const BezierSpline &spline, MutableSpan<float> parameters) +static void calculate_bezier_lengths(const BezierSpline &spline, MutableSpan<float> lengths) { Span<int> offsets = spline.control_point_offsets(); - Span<float> lengths = spline.evaluated_lengths(); - const float total_length = spline.length(); - const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length; - + Span<float> lengths_eval = spline.evaluated_lengths(); for (const int i : IndexRange(1, spline.size() - 1)) { - parameters[i] = lengths[offsets[i] - 1] * total_length_inverse; + lengths[i] = lengths_eval[offsets[i] - 1]; } } /** * The parameter for poly splines is simply the evaluated lengths divided by the total length. */ -static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<float> parameters) +static void calculate_poly_length(const PolySpline &spline, MutableSpan<float> lengths) { - Span<float> lengths = spline.evaluated_lengths(); - const float total_length = spline.length(); - const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length; - - for (const int i : IndexRange(1, spline.size() - 1)) { - parameters[i] = lengths[i - 1] * total_length_inverse; + Span<float> lengths_eval = spline.evaluated_lengths(); + if (spline.is_cyclic()) { + lengths.drop_front(1).copy_from(lengths_eval.drop_back(1)); + } + else { + lengths.drop_front(1).copy_from(lengths_eval); } } @@ -82,70 +86,100 @@ static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<floa * each point is not well defined. So instead, treat the control points as if they were a poly * spline. */ -static void calculate_nurbs_parameters(const NURBSpline &spline, MutableSpan<float> parameters) +static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float> lengths) { Span<float3> positions = spline.positions(); Array<float> control_point_lengths(spline.size()); - float length = 0.0f; for (const int i : IndexRange(positions.size() - 1)) { - parameters[i] = length; + lengths[i] = length; length += float3::distance(positions[i], positions[i + 1]); } - - const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length; - for (float ¶meter : parameters) { - parameter *= total_length_inverse; - } + lengths.last() = length; } -static Array<float> curve_parameter_point_domain(const CurveEval &curve) +static Array<float> curve_length_point_domain(const CurveEval &curve) { Span<SplinePtr> splines = curve.splines(); Array<int> offsets = curve.control_point_offsets(); const int total_size = offsets.last(); - Array<float> parameters(total_size); + Array<float> lengths(total_size); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { const Spline &spline = *splines[i]; - MutableSpan spline_factors{parameters.as_mutable_span().slice(offsets[i], spline.size())}; + MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())}; spline_factors.first() = 0.0f; switch (splines[i]->type()) { case Spline::Type::Bezier: { - calculate_bezier_parameters(static_cast<const BezierSpline &>(spline), spline_factors); + calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors); break; } case Spline::Type::Poly: { - calculate_poly_parameters(static_cast<const PolySpline &>(spline), spline_factors); + calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors); break; } case Spline::Type::NURBS: { - calculate_nurbs_parameters(static_cast<const NURBSpline &>(spline), spline_factors); + calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors); break; } } } }); - return parameters; + return lengths; } -static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, - const IndexMask mask, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_curve_parameter_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) { if (domain == ATTR_DOMAIN_POINT) { - Array<float> parameters = curve_parameter_point_domain(curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters)); + Span<SplinePtr> splines = curve.splines(); + Array<float> values = curve_length_point_domain(curve); + + const Array<int> offsets = curve.control_point_offsets(); + for (const int i_spline : curve.splines().index_range()) { + const Spline &spline = *splines[i_spline]; + const float spline_length = spline.length(); + const float spline_length_inv = spline_length == 0.0f ? 0.0f : 1.0f / spline_length; + for (const int i : IndexRange(spline.size())) { + values[offsets[i_spline] + i] *= spline_length_inv; + } + } + return VArray<float>::ForContainer(std::move(values)); } if (domain == ATTR_DOMAIN_CURVE) { - Array<float> parameters = curve_parameter_spline_domain(curve, mask); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters)); + Array<float> values = curve.accumulated_spline_lengths(); + const float total_length_inv = values.last() == 0.0f ? 0.0f : 1.0f / values.last(); + for (const int i : mask) { + values[i] *= total_length_inv; + } + return VArray<float>::ForContainer(std::move(values)); } + return {}; +} - return nullptr; +static VArray<float> construct_curve_length_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) +{ + if (domain == ATTR_DOMAIN_POINT) { + Array<float> lengths = curve_length_point_domain(curve); + return VArray<float>::ForContainer(std::move(lengths)); + } + + if (domain == ATTR_DOMAIN_CURVE) { + if (curve.splines().size() == 1) { + Array<float> lengths(1, 0.0f); + return VArray<float>::ForContainer(std::move(lengths)); + } + + Array<float> lengths = curve_length_spline_domain(curve, mask); + return VArray<float>::ForContainer(std::move(lengths)); + } + + return {}; } class CurveParameterFieldInput final : public fn::FieldInput { @@ -155,9 +189,9 @@ class CurveParameterFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -169,11 +203,11 @@ class CurveParameterFieldInput final : public fn::FieldInput { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve) { - return construct_curve_parameter_gvarray(*curve, mask, domain, scope); + return construct_curve_parameter_varray(*curve, mask, domain); } } } - return nullptr; + return {}; } uint64_t hash() const override @@ -188,20 +222,62 @@ class CurveParameterFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_parameter_exec(GeoNodeExecParams params) +class CurveLengthFieldInput final : public fn::FieldInput { + public: + CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final + { + if (const GeometryComponentFieldContext *geometry_context = + dynamic_cast<const GeometryComponentFieldContext *>(&context)) { + + const GeometryComponent &component = geometry_context->geometry_component(); + const AttributeDomain domain = geometry_context->domain(); + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve) { + return construct_curve_length_varray(*curve, mask, domain); + } + } + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 345634563454; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) { Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()}; + Field<float> length_field{std::make_shared<CurveLengthFieldInput>()}; params.set_output("Factor", std::move(parameter_field)); + params.set_output("Length", std::move(length_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_parameter_cc void register_node_type_geo_curve_parameter() { - static bNodeType ntype; + namespace file_ns = blender::nodes::node_geo_curve_parameter_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec; - ntype.declare = blender::nodes::geo_node_curve_parameter_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index a755d47cc6a..a2ca41d8e19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -21,34 +21,44 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc { -static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) .min(1) .max(256) - .subtype(PROP_UNSIGNED); + .subtype(PROP_UNSIGNED) + .description(N_("The number of evaluated points on the curve")); b.add_input<decl::Vector>(N_("Start")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the start control point of the curve")); b.add_input<decl::Vector>(N_("Start Handle")) .default_value({-0.5f, 0.5f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End Handle")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("Position of the start handle used to define the shape of the curve. In Offset mode, " + "relative to Start point")); + b.add_input<decl::Vector>(N_("End Handle")) + .subtype(PROP_TRANSLATION) + .description( + N_("Position of the end handle used to define the shape of the curve. In Offset mode, " + "relative to End point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({1.0f, 0.0f, 0.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the end control point of the curve")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *) MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__); @@ -108,7 +118,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( return curve; } -static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveBezierSegment *node_storage = (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage; @@ -125,20 +135,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc void register_node_type_geo_curve_primitive_bezier_segment() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveBezierSegment", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index bf4f22d6578..f56571241f9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -21,33 +21,48 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_circle_cc { -static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Resolution")).default_value(32).min(3).max(512); + b.add_input<decl::Int>(N_("Resolution")) + .default_value(32) + .min(3) + .max(512) + .description(N_("Number of points on the circle")); b.add_input<decl::Vector>(N_("Point 1")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); b.add_input<decl::Vector>(N_("Point 2")) .default_value({0.0f, 1.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); b.add_input<decl::Vector>(N_("Point 3")) .default_value({1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance of the points from the origin")); b.add_output<decl::Geometry>(N_("Curve")); b.add_output<decl::Vector>(N_("Center")); } -static void geo_node_curve_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveCircle), __func__); @@ -56,7 +71,7 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *) node->storage; @@ -70,11 +85,16 @@ static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNo bNodeSocket *center_socket = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); + nodeSetSocketAvailability( + ntree, start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); } static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3) @@ -173,7 +193,7 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio return curve; } -static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *)params.node().storage; @@ -204,22 +224,24 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_circle_cc void register_node_type_geo_curve_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 5b215797052..321fe6f2a9e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -21,25 +21,34 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_line_cc { -static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Vector>(N_("Start")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("Direction")).default_value({0.0f, 0.0f, 1.0f}); - b.add_input<decl::Float>(N_("Length")).default_value(1.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Vector>(N_("Start")) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first control point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({0.0f, 0.0f, 1.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the second control point")); + b.add_input<decl::Vector>(N_("Direction")) + .default_value({0.0f, 0.0f, 1.0f}) + .description( + N_("Direction the line is going in. The length of this vector does not matter")); + b.add_input<decl::Float>(N_("Length")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance between the two points")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveLine), __func__); @@ -48,7 +57,7 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n node->storage = data; } -static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *) node->storage; @@ -59,10 +68,11 @@ static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode bNodeSocket *direction_socket = p2_socket->next; bNodeSocket *length_socket = direction_socket->next; - nodeSetSocketAvailability(p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); - nodeSetSocketAvailability(direction_socket, - mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability(ntree, p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); + nodeSetSocketAvailability( + ntree, direction_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability( + ntree, length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); } static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end) @@ -100,7 +110,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start return curve; } -static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveLine *node_storage = @@ -122,20 +132,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_line_cc void register_node_type_geo_curve_primitive_line() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveLine", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc index 6041ddee02d..92a9b1b4966 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc @@ -17,22 +17,28 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc { -static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) .min(3) .max(256) - .subtype(PROP_UNSIGNED); + .subtype(PROP_UNSIGNED) + .description(N_("The number of edges on the curve")); b.add_input<decl::Vector>(N_("Start")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first control point")); b.add_input<decl::Vector>(N_("Middle")) .default_value({0.0f, 2.0f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the middle control point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({1.0f, 0.0f, 0.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the last control point")); b.add_output<decl::Geometry>(N_("Curve")); } @@ -58,7 +64,7 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1, return curve; } -static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve( params.extract_input<float3>("Start"), @@ -68,17 +74,19 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc void register_node_type_geo_curve_primitive_quadratic_bezier() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index 7260da05a8d..53e301ecad7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -19,46 +19,70 @@ #include "UI_resources.h" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc { -static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Height")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Float>(N_("Width")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Height")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The Y axis size of the shape")); b.add_input<decl::Float>(N_("Bottom Width")) .default_value(4.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Top Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Offset")).default_value(1.0f).subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Top Width")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Offset")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description( + N_("For Parallelogram, the relative X difference between the top and bottom edges. For " + "Trapezoid, the amount to move the top edge in the positive X axis")); b.add_input<decl::Float>(N_("Bottom Height")) .default_value(3.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Top Height")).default_value(1.0f).subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The distance between the bottom point and the X axis")); + b.add_input<decl::Float>(N_("Top Height")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("The distance between the top point and the X axis")); b.add_input<decl::Vector>(N_("Point 1")) .default_value({-1.0f, -1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 2")) .default_value({1.0f, -1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 3")) .default_value({1.0f, 1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 4")) .default_value({-1.0f, 1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveQuad), __func__); @@ -66,7 +90,7 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), node->storage = data; } -static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( @@ -85,34 +109,34 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntre bNodeSocket *p4 = p3->next; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - nodeSetSocketAvailability(sock, false); + nodeSetSocketAvailability(ntree, sock, false); } if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); - nodeSetSocketAvailability(offset, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); + nodeSetSocketAvailability(ntree, offset, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { - nodeSetSocketAvailability(bottom, true); - nodeSetSocketAvailability(top, true); - nodeSetSocketAvailability(offset, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, bottom, true); + nodeSetSocketAvailability(ntree, top, true); + nodeSetSocketAvailability(ntree, offset, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(bottom_height, true); - nodeSetSocketAvailability(top_height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, bottom_height, true); + nodeSetSocketAvailability(ntree, top_height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { - nodeSetSocketAvailability(p1, true); - nodeSetSocketAvailability(p2, true); - nodeSetSocketAvailability(p3, true); - nodeSetSocketAvailability(p4, true); + nodeSetSocketAvailability(ntree, p1, true); + nodeSetSocketAvailability(ntree, p2, true); + nodeSetSocketAvailability(ntree, p3, true); + nodeSetSocketAvailability(ntree, p4, true); } } @@ -171,7 +195,7 @@ static void create_kite_curve(MutableSpan<float3> positions, positions[3] = float3(-width / 2.0f, 0, 0); } -static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage; @@ -229,18 +253,20 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc void register_node_type_geo_curve_primitive_quadrilateral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout; - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveQuad", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc index 1dc9cd7f107..3be119a073f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc @@ -18,20 +18,34 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_spiral_cc { -static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(32) .min(1) .max(1024) - .subtype(PROP_UNSIGNED); - b.add_input<decl::Float>(N_("Rotations")).default_value(2.0f).min(0.0f); - b.add_input<decl::Float>(N_("Start Radius")).default_value(1.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("End Radius")).default_value(2.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Height")).default_value(2.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Bool>(N_("Reverse")); + .subtype(PROP_UNSIGNED) + .description(N_("Number of points in one rotation of the spiral")); + b.add_input<decl::Float>(N_("Rotations")) + .default_value(2.0f) + .min(0.0f) + .description(N_("Number of times the spiral makes a full rotation")); + b.add_input<decl::Float>(N_("Start Radius")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("Horizontal Distance from the Z axis at the start of the spiral")); + b.add_input<decl::Float>(N_("End Radius")) + .default_value(2.0f) + .subtype(PROP_DISTANCE) + .description(N_("Horizontal Distance from the Z axis at the end of the spiral")); + b.add_input<decl::Float>(N_("Height")) + .default_value(2.0f) + .subtype(PROP_DISTANCE) + .description(N_("The height perpendicular to the base of the spiral")); + b.add_input<decl::Bool>(N_("Reverse")) + .description(N_("Switch the direction from clockwise to counterclockwise")); b.add_output<decl::Geometry>(N_("Curve")); } @@ -67,7 +81,7 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations, return curve; } -static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f); if (rotations == 0.0f) { @@ -85,14 +99,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc void register_node_type_geo_curve_primitive_spiral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index b5bafce17c6..731be0f0f49 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -18,21 +18,33 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_star_cc { -static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Points")).default_value(8).min(3).max(256).subtype(PROP_UNSIGNED); + b.add_input<decl::Int>(N_("Points")) + .default_value(8) + .min(3) + .max(256) + .subtype(PROP_UNSIGNED) + .description(N_("Number of points on each of the circles")); b.add_input<decl::Float>(N_("Inner Radius")) .default_value(1.0f) .min(0.0f) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("Radius of the inner circle; can be larger than outer radius")); b.add_input<decl::Float>(N_("Outer Radius")) .default_value(2.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Twist")).subtype(PROP_ANGLE); + .subtype(PROP_DISTANCE) + .description(N_("Radius of the outer circle; can be smaller than inner radius")); + b.add_input<decl::Float>(N_("Twist")) + .subtype(PROP_ANGLE) + .description(N_("The counterclockwise rotation of the inner set of points")); b.add_output<decl::Geometry>(N_("Curve")); + b.add_output<decl::Bool>(N_("Outer Points")) + .field_source() + .description(N_("An attribute field with a selection of the outer points")); } static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, @@ -57,26 +69,49 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, spline->attributes.reallocate(spline->size()); curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); + return curve; } -static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) +static void create_selection_output(CurveComponent &component, + StrongAnonymousAttributeID &r_attribute) +{ + OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>( + r_attribute.get(), ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + for (int i : selection.index_range()) { + selection[i] = i % 2 == 0; + } + attribute.save(); +} + +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_star_curve( std::max(params.extract_input<float>("Inner Radius"), 0.0f), std::max(params.extract_input<float>("Outer Radius"), 0.0f), params.extract_input<float>("Twist"), std::max(params.extract_input<int>("Points"), 3)); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); -} + GeometrySet output = GeometrySet::create_with_curve(curve.release()); -} // namespace blender::nodes + if (params.output_is_required("Outer Points")) { + StrongAnonymousAttributeID attribute_output("Outer Points"); + create_selection_output(output.get_component_for_write<CurveComponent>(), attribute_output); + params.set_output("Outer Points", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_output), params.attribute_producer_name())); + } + params.set_output("Curve", std::move(output)); +} +} // namespace blender::nodes::node_geo_curve_primitive_star_cc void register_node_type_geo_curve_primitive_star() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index 945dac5650b..dec72eb61bb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -26,15 +26,12 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_curve_resample_cc { -namespace blender::nodes { - -static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); + b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field(); b.add_input<decl::Float>(N_("Length")) .default_value(0.1f) @@ -44,12 +41,12 @@ static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN( sizeof(NodeGeometryCurveResample), __func__); @@ -58,22 +55,23 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; - bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; + bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } struct SampleModeParam { GeometryNodeCurveResampleMode mode; std::optional<Field<float>> length; std::optional<Field<int>> count; + Field<bool> selection; }; static SplinePtr resample_spline(const Spline &src, const int count) @@ -122,7 +120,7 @@ static SplinePtr resample_spline(const Spline &src, const int count) std::optional<GMutableSpan> output_attribute = dst->attributes.get_for_write( attribute_id); if (output_attribute) { - src.sample_with_index_factors(*src.interpolate_to_evaluated(*input_attribute), + src.sample_with_index_factors(src.interpolate_to_evaluated(*input_attribute), uniform_samples, *output_attribute); return true; @@ -145,8 +143,8 @@ static SplinePtr resample_spline_evaluated(const Spline &src) dst->positions().copy_from(src.evaluated_positions()); dst->positions().copy_from(src.evaluated_positions()); - src.interpolate_to_evaluated(src.radii())->materialize(dst->radii()); - src.interpolate_to_evaluated(src.tilts())->materialize(dst->tilts()); + src.interpolate_to_evaluated(src.radii()).materialize(dst->radii()); + src.interpolate_to_evaluated(src.tilts()).materialize(dst->tilts()); src.attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { @@ -154,7 +152,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src) if (dst->attributes.create(attribute_id, meta_data.data_type)) { std::optional<GMutableSpan> dst_attribute = dst->attributes.get_for_write(attribute_id); if (dst_attribute) { - src.interpolate_to_evaluated(*src_attribute)->materialize(dst_attribute->data()); + src.interpolate_to_evaluated(*src_attribute).materialize(dst_attribute->data()); return true; } } @@ -183,42 +181,64 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_COUNT) { fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(*mode_param.count); + evaluator.add(mode_param.selection); evaluator.evaluate(); const VArray<int> &cuts = evaluator.get_evaluated<int>(0); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(1); threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { BLI_assert(mode_param.count); - output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1)); + if (selections[i]) { + output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1)); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) { fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(*mode_param.length); + evaluator.add(mode_param.selection); evaluator.evaluate(); const VArray<float> &lengths = evaluator.get_evaluated<float>(0); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(1); threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - /* Don't allow asymptotic count increase for low resolution values. */ - const float divide_length = std::max(lengths[i], 0.0001f); - const float spline_length = input_splines[i]->length(); - const int count = std::max(int(spline_length / divide_length) + 1, 1); - output_splines[i] = resample_spline(*input_splines[i], count); + if (selections[i]) { + /* Don't allow asymptotic count increase for low resolution values. */ + const float divide_length = std::max(lengths[i], 0.0001f); + const float spline_length = input_splines[i]->length(); + const int count = std::max(int(spline_length / divide_length) + 1, 1); + output_splines[i] = resample_spline(*input_splines[i], count); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_EVALUATED) { + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(mode_param.selection); + evaluator.evaluate(); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(0); + threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - output_splines[i] = resample_spline_evaluated(*input_splines[i]); + if (selections[i]) { + output_splines[i] = resample_spline_evaluated(*input_splines[i]); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } - output_curve->attributes = input_curve->attributes; - return output_curve; } @@ -235,7 +255,7 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_resample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -244,6 +264,8 @@ static void geo_node_resample_exec(GeoNodeExecParams params) SampleModeParam mode_param; mode_param.mode = mode; + mode_param.selection = params.extract_input<Field<bool>>("Selection"); + if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) { Field<int> count = params.extract_input<Field<int>>("Count"); if (count < 1) { @@ -263,19 +285,21 @@ static void geo_node_resample_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_resample_cc void register_node_type_geo_curve_resample() { + namespace file_ns = blender::nodes::node_geo_curve_resample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_resample_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update); - ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index b1dc45a426a..d07e89ec7f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -20,16 +20,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_reverse_cc void register_node_type_geo_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 31b38c0dce7..b81860ca9b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_sample_cc { -static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")) .only_realized_data() @@ -38,12 +38,12 @@ static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Normal")).dependent_field(); } -static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_type_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN( sizeof(NodeGeometryCurveSample), __func__); @@ -51,7 +51,7 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -59,8 +59,8 @@ static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length = factor->next; - nodeSetSocketAvailability(factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data) @@ -229,7 +229,7 @@ static Field<float> get_length_input_field(const GeoNodeExecParams ¶ms, return Field<float>(std::move(process_op), 0); } -static void geo_node_curve_sample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -271,20 +271,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params) params.set_output("Normal", Field<float3>(sample_op, 2)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_sample_cc void register_node_type_geo_curve_sample() { + namespace file_ns = blender::nodes::node_geo_curve_sample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec; - ntype.declare = blender::nodes::geo_node_curve_sample_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_type_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index 8b0a6ca840c..d769228f9e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -21,24 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_set_handles_cc { -static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSetHandles *node_storage = (NodeGeometryCurveSetHandles *)params.node().storage; @@ -130,21 +128,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) } params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_set_handles_cc void register_node_type_geo_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index ae4453929ac..1d859c8555f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -23,23 +23,21 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_spline_type_cc { -static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,7 +236,7 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType *storage = (const NodeGeometryCurveSplineType *)params.node().storage; @@ -288,21 +286,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_spline_type_cc void register_node_type_geo_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index b52de822c22..6de188fc1c4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -25,13 +25,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_curve_subdivide_cc { -namespace blender::nodes { - -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field(); @@ -326,7 +322,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<int> cuts_field = params.extract_input<Field<int>>("Cuts"); @@ -355,14 +351,16 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_subdivide_cc void register_node_type_geo_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index 1977b465de4..ff3e85cb6b7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_to_mesh_cc { -static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Geometry>(N_("Profile Curve")) @@ -54,7 +54,7 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, } } -static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve"); @@ -72,14 +72,16 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(curve_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_mesh_cc void register_node_type_geo_curve_to_mesh() { + namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 38d7fb99e87..1901097c369 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -27,8 +27,22 @@ #include "node_geometry_util.hh" namespace blender::nodes { +void curve_create_default_rotation_attribute(Span<float3> tangents, + Span<float3> normals, + MutableSpan<float3> rotations) +{ + threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { + for (const int i : range) { + rotations[i] = + float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); + } + }); +} +} // namespace blender::nodes + +namespace blender::nodes::node_geo_curve_to_points_cc { -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); @@ -39,12 +53,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Rotation")).field_source(); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -53,7 +67,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -61,8 +75,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, @@ -113,7 +127,7 @@ static GMutableSpan ensure_point_attribute(PointCloudComponent &points, points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); BLI_assert(attribute); - return attribute.varray->get_internal_span(); + return attribute.varray.get_internal_span(); } template<typename T> @@ -194,7 +208,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -203,7 +217,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.interpolate_to_evaluated(spline_span)->materialize(dst.slice(offset, size).data()); + spline.interpolate_to_evaluated(spline_span).materialize(dst.slice(offset, size).data()); } if (!data.tangents.is_empty()) { @@ -233,7 +247,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, spline.sample_with_index_factors<float3>( spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size)); - spline.sample_with_index_factors<float>(*spline.interpolate_to_evaluated(spline.radii()), + spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()), uniform_samples, data.radii.slice(offset, size)); @@ -244,7 +258,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, dst.slice(offset, size)); } @@ -289,19 +303,7 @@ static void copy_spline_domain_attributes(const CurveEval &curve, ATTR_DOMAIN_CURVE); } -void curve_create_default_rotation_attribute(Span<float3> tangents, - Span<float3> normals, - MutableSpan<float3> rotations) -{ - threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { - for (const int i : range) { - rotations[i] = - float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); - } - }); -} - -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -374,20 +376,22 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_points_cc void register_node_type_geo_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 4e1a2910c7c..127164b0ab0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -22,11 +22,11 @@ #include "node_geometry_util.hh" -using blender::attribute_math::mix2; +namespace blender::nodes::node_geo_curve_trim_cc { -namespace blender::nodes { +using blender::attribute_math::mix2; -static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field(); @@ -48,12 +48,12 @@ static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim), __func__); @@ -62,7 +62,7 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -72,10 +72,10 @@ static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *start_len = end_fac->next; bNodeSocket *end_len = start_len->next; - nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); - nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } struct TrimLocation { @@ -216,9 +216,9 @@ static PolySpline trim_nurbs_spline(const Spline &spline, attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); linear_trim_to_output_data<T>( - start, end, eval_data->get_internal_span(), dst->typed<T>()); + start, end, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -227,13 +227,13 @@ static PolySpline trim_nurbs_spline(const Spline &spline, linear_trim_to_output_data<float3>( start, end, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); linear_trim_to_output_data<float>( - start, end, evaluated_radii->get_internal_span(), new_spline.radii()); + start, end, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); linear_trim_to_output_data<float>( - start, end, evaluated_tilts->get_internal_span(), new_spline.tilts()); + start, end, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } @@ -427,8 +427,8 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id); attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); - to_single_point_data<T>(trim, eval_data->get_internal_span(), dst->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -436,11 +436,11 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); - to_single_point_data<float>(trim, evaluated_radii->get_internal_span(), new_spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); - to_single_point_data<float>(trim, evaluated_tilts->get_internal_span(), new_spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } @@ -532,7 +532,7 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, }); } -static void geo_node_curve_trim_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -557,18 +557,20 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_trim_cc void register_node_type_geo_curve_trim() { + namespace file_ns = blender::nodes::node_geo_curve_trim_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout; - ntype.declare = blender::nodes::geo_node_curve_trim_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index b0df6428a06..055e44998cb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -29,58 +29,24 @@ #include "node_geometry_util.hh" -using blender::bke::CustomDataAttributes; - /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); namespace blender::nodes { -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Bool>(N_("Selection")) - .default_value(true) - .hide_value() - .supports_field() - .description(N_("The parts of the geometry to be deleted")); - b.add_output<decl::Geometry>(N_("Geometry")); -} - -static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - const bNode *node = static_cast<bNode *>(ptr->data); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); - /* Only show the mode when it is relevant. */ - if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); - } -} - -static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node) -{ - NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( - sizeof(NodeGeometryDeleteGeometry), __func__); - data->domain = ATTR_DOMAIN_POINT; - data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; - - node->storage = data; -} +using blender::bke::CustomDataAttributes; template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask) { @@ -138,7 +104,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!domains.contains(attribute.domain)) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -149,7 +115,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); out_span.copy_from(span); }); @@ -178,7 +144,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (domain != attribute.domain) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -189,7 +155,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data(span, out_span, mask); }); @@ -1209,7 +1175,45 @@ void separate_geometry(GeometrySet &geometry_set, r_is_error = !some_valid_domain && geometry_set.has_realized_data(); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_delete_geometry_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Bool>(N_("Selection")) + .default_value(true) + .hide_value() + .supports_field() + .description(N_("The parts of the geometry to be deleted")); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const bNode *node = static_cast<bNode *>(ptr->data); + const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); + /* Only show the mode when it is relevant. */ + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + } +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( + sizeof(NodeGeometryDeleteGeometry), __func__); + data->domain = ATTR_DOMAIN_POINT; + data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; + + node->storage = data; +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -1236,10 +1240,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_delete_geometry_cc void register_node_type_geo_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); @@ -1249,10 +1255,10 @@ void register_node_type_geo_delete_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 115ad09a9e6..adb698b8f7a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -36,11 +36,9 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_distribute_points_on_faces_cc { -namespace blender::nodes { - -static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -60,26 +58,26 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source(); } -static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_points_on_faces_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next; bNodeSocket *sock_density = sock_density_max->next; bNodeSocket *sock_density_factor = sock_density->next; - nodeSetSocketAvailability(sock_distance_min, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density_max, + nodeSetSocketAvailability(ntree, + sock_distance_min, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); - nodeSetSocketAvailability(sock_density_factor, + nodeSetSocketAvailability( + ntree, sock_density_max, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); + nodeSetSocketAvailability( + ntree, sock_density, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); + nodeSetSocketAvailability(ntree, + sock_density_factor, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); } @@ -313,7 +311,7 @@ BLI_NOINLINE static void propagate_existing_attributes( bary_coords, looptri_indices, source_attribute.domain, - *source_attribute.varray, + source_attribute.varray, out_span); attribute_out.save(); } @@ -526,7 +524,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set, mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs); } -static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -568,10 +566,12 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc void register_node_type_geo_distribute_points_on_faces() { + namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -579,10 +579,10 @@ void register_node_type_geo_distribute_points_on_faces() "Distribute Points on Faces", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update); + node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update); node_type_size(&ntype, 170, 100, 320); - ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index f562fb29e90..d23a18ba37b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -33,12 +33,13 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection) { - const BMeshCreateParams bmcp = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; const BMAllocTemplate allocsize = {0, 0, 0, 0}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); - BMeshFromMeshParams params{}; - BM_mesh_bm_from_me(bm, &mesh, ¶ms); + BMeshFromMeshParams bmesh_from_mesh_params{}; + BM_mesh_bm_from_me(bm, &mesh, &bmesh_from_mesh_params); BM_mesh_elem_table_ensure(bm, BM_EDGE); for (const int i : selection) { @@ -56,7 +57,7 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection) return result; } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -81,14 +82,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_edge_split_cc void register_node_type_geo_edge_split() { + namespace file_ns = blender::nodes::node_geo_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc index e1c72fbd438..c56d920fac5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc @@ -32,9 +32,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_image_texture_cc { -static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Image>(N_("Image")).hide_label(); b.add_input<decl::Vector>(N_("Vector")) @@ -45,13 +45,13 @@ static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field(); } -static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); } -static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN( sizeof(NodeGeometryImageTexture), __func__); @@ -82,7 +82,7 @@ class ImageFieldsFunction : public fn::MultiFunction { image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_); if (image_buffer_ == nullptr) { - throw std::runtime_error("cannot aquire image buffer"); + throw std::runtime_error("cannot acquire image buffer"); } if (image_buffer_->rect_float == nullptr) { @@ -370,7 +370,7 @@ class ImageFieldsFunction : public fn::MultiFunction { } }; -static void geo_node_image_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { auto return_default = [&]() { params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); @@ -410,20 +410,22 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params) params.set_output("Alpha", Field<float>(image_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_image_texture_cc void register_node_type_geo_image_texture(void) { + namespace file_ns = blender::nodes::node_geo_image_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::geo_node_image_texture_declare; - ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout; - node_type_init(&ntype, blender::nodes::geo_node_image_texture_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index b8df545d073..dae8fda2099 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -16,15 +16,15 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_handles_cc { -static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Left")).field_source(); b.add_output<decl::Vector>(N_("Right")).field_source(); } -static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left"); Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right"); @@ -32,15 +32,17 @@ static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) params.set_output("Right", std::move(right_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_handles_cc void register_node_type_geo_input_curve_handles() { + namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_input_curve_handles_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc index f32db3842db..5ba85b6f34e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_tilt_cc { -static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Tilt")).field_source(); } -static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt"); params.set_output("Tilt", std::move(tilt_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_tilt_cc void register_node_type_geo_input_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_input_curve_tilt_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc index 37d5bac0325..d2e103a093a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_id_cc { -static void geo_node_input_id_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("ID")).field_source(); } -static void geo_node_input_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()}; params.set_output("ID", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_id_cc void register_node_type_geo_input_id() { + namespace file_ns = blender::nodes::node_geo_input_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec; - ntype.declare = blender::nodes::geo_node_input_id_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc index 6200ac5e7a8..74cddfc6a4a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_index_cc { -static void geo_node_input_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Index")).field_source(); } -static void geo_node_input_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> index_field{std::make_shared<fn::IndexFieldInput>()}; params.set_output("Index", std::move(index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_index_cc void register_node_type_geo_input_index() { + namespace file_ns = blender::nodes::node_geo_input_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec; - ntype.declare = blender::nodes::geo_node_input_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc index fc41188dee5..1b6e3c8fc68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc @@ -19,33 +19,35 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_cc { -static void geo_node_input_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Material>(N_("Material")); } -static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "material", 0, "", ICON_NONE); } -static void geo_node_input_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = (Material *)params.node().id; params.set_output("Material", material); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_cc void register_node_type_geo_input_material() { + namespace file_ns = blender::nodes::node_geo_input_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0); - ntype.draw_buttons = blender::nodes::geo_node_input_material_layout; - ntype.declare = blender::nodes::geo_node_input_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc index 5d5d9e40032..4df218eb669 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_index_cc { -static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Material Index")).field_source(); } -static void geo_node_input_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index"); params.set_output("Material Index", std::move(material_index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_index_cc void register_node_type_geo_input_material_index() { + namespace file_ns = blender::nodes::node_geo_input_material_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_index_exec; - ntype.declare = blender::nodes::geo_node_input_material_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 92b89313d23..6e63354a31a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -24,26 +24,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_normal_cc { -static void geo_node_input_normal_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Normal")).field_source(); } -static GVArrayPtr mesh_face_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_face_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) && CustomData_has_layer(&mesh.pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, polys.size())); + return VArray<float3>::ForSpan({(const float3 *)data, polys.size()}); } auto normal_fn = [verts, polys, loops](const int i) -> float3 { @@ -53,24 +52,21 @@ static GVArrayPtr mesh_face_normals(const Mesh &mesh, return normal; }; - return std::make_unique< - fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>( - mask.min_array_size(), mask.min_array_size(), normal_fn); + return VArray<float3>::ForFunc(mask.min_array_size(), normal_fn); } -static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_vertex_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) && CustomData_has_layer(&mesh.vdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, mesh.totvert)); + return VArray<float3>::ForSpan({(const float3 *)data, mesh.totvert}); } /* If the normals are dirty, they must be recalculated for the output of this node's field @@ -91,14 +87,14 @@ static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, nullptr, (float(*)[3])normals.data()); - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } -static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component, +static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { Span<MVert> verts{mesh.mvert, mesh.totvert}; Span<MEdge> edges{mesh.medge, mesh.totedge}; @@ -107,18 +103,18 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c switch (domain) { case ATTR_DOMAIN_FACE: { - return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_face_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_POINT: { - return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_vertex_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_EDGE: { /* In this case, start with vertex normals and convert to the edge domain, since the * conversion from edges to vertices is very simple. Use the full mask since the edges * might use the vertex normal from any index. */ - GVArrayPtr vert_normals = mesh_vertex_normals( + GVArray vert_normals = mesh_vertex_normals( mesh, verts, polys, loops, IndexRange(verts.size())); - Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>(); + Span<float3> vert_normals_span = vert_normals.get_internal_span().typed<float3>(); Array<float3> edge_normals(mask.min_array_size()); /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid @@ -130,23 +126,21 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c .normalized(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(edge_normals)); + return VArray<float3>::ForContainer(std::move(edge_normals)); } case ATTR_DOMAIN_CORNER: { /* The normals on corners are just the mesh's face normals, so start with the face normal * array and copy the face normal for each of its corners. */ - GVArrayPtr face_normals = mesh_face_normals( + VArray<float3> face_normals = mesh_face_normals( mesh, verts, polys, loops, IndexRange(polys.size())); /* In this case using the mesh component's generic domain interpolation is fine, the data * will still be normalized, since the face normal is just copied to every corner. */ - GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain( + return mesh_component.attribute_try_adapt_domain<float3>( std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); - return scope.add_value(std::move(loop_normals)).get(); } default: - return nullptr; + return {}; } } @@ -204,9 +198,9 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve) return normals; } -static const GVArray *construct_curve_normal_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -220,20 +214,18 @@ static const GVArray *construct_curve_normal_gvarray(const CurveComponent &compo * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_normals()); + return VArray<float3>::ForSpan(spline.evaluated_normals()); } Array<float3> normals = curve_normal_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_normals = curve_normal_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_normals)); - GVArrayPtr spline_normals = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_normals)).get(); + VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); + return component.attribute_try_adapt_domain<float3>( + std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; @@ -246,9 +238,9 @@ class NormalFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -260,7 +252,7 @@ class NormalFieldInput final : public fn::FieldInput { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope); @@ -270,7 +262,7 @@ class NormalFieldInput final : public fn::FieldInput { return construct_curve_normal_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -285,20 +277,22 @@ class NormalFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_normal_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> normal_field{std::make_shared<NormalFieldInput>()}; params.set_output("Normal", std::move(normal_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_normal_cc void register_node_type_geo_input_normal() { + namespace file_ns = blender::nodes::node_geo_input_normal_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec; - ntype.declare = blender::nodes::geo_node_input_normal_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc index a8477d4bc4f..8322831a871 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_position_cc { -static void geo_node_input_position_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Position")).field_source(); } -static void geo_node_input_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> position_field{AttributeFieldInput::Create<float3>("position")}; params.set_output("Position", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_position_cc void register_node_type_geo_input_position() { + namespace file_ns = blender::nodes::node_geo_input_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec; - ntype.declare = blender::nodes::geo_node_input_position_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc index 6d2c4c38cbe..26fb74f5a5b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_radius_cc { -static void geo_node_input_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source(); } -static void geo_node_input_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> radius_field = AttributeFieldInput::Create<float>("radius"); params.set_output("Radius", std::move(radius_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_radius_cc void register_node_type_geo_input_radius() { + namespace file_ns = blender::nodes::node_geo_input_radius_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_radius_exec; - ntype.declare = blender::nodes::geo_node_input_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index dcd14b1c054..3efe8577e51 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_shade_smooth_cc { -static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Smooth")).field_source(); } -static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth"); params.set_output("Smooth", std::move(shade_smooth_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_shade_smooth_cc void register_node_type_geo_input_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_input_shade_smooth_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc index a8ee6dd8b12..5f833445a76 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_cyclic_cc { -static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Cyclic")).field_source(); } -static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic"); params.set_output("Cyclic", std::move(cyclic_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_cyclic_cc void register_node_type_geo_input_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_input_spline_cyclic_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 895efa6f0ed..998fce5841b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -18,38 +18,32 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_length_cc { -static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Length")).field_source(); } -static const GVArray *construct_spline_length_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_spline_length_gvarray(const CurveComponent &component, + const AttributeDomain domain, + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } Span<SplinePtr> splines = curve->splines(); auto length_fn = [splines](int i) { return splines[i]->length(); }; if (domain == ATTR_DOMAIN_CURVE) { - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); + return VArray<float>::ForFunc(splines.size(), length_fn); } if (domain == ATTR_DOMAIN_POINT) { - GVArrayPtr length = std::make_unique< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); - return scope - .add_value(component.attribute_try_adapt_domain( - std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT)) - .get(); + VArray<float> length = VArray<float>::ForFunc(splines.size(), length_fn); + return component.attribute_try_adapt_domain<float>( + std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } return nullptr; @@ -62,9 +56,9 @@ class SplineLengthFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -76,7 +70,7 @@ class SplineLengthFieldInput final : public fn::FieldInput { return construct_spline_length_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -91,20 +85,22 @@ class SplineLengthFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_spline_length_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> length_field{std::make_shared<SplineLengthFieldInput>()}; params.set_output("Length", std::move(length_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_length_cc void register_node_type_geo_input_spline_length() { + namespace file_ns = blender::nodes::node_geo_input_spline_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_length_exec; - ntype.declare = blender::nodes::geo_node_input_spline_length_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc index 75fb8a13d38..77b6e27e6a2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_resolution_cc { -static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Resolution")).field_source(); } -static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution"); params.set_output("Resolution", std::move(resolution_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_resolution_cc void register_node_type_geo_input_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_input_spline_resolution_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 6b1736fe2ac..0502f64ecb7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_tangent_cc { -static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Tangent")).field_source(); } @@ -84,9 +84,9 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve) return tangents; } -static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -100,20 +100,19 @@ static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &comp * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_tangents()); + return VArray<float3>::ForSpan(spline.evaluated_tangents()); } Array<float3> tangents = curve_tangent_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(tangents)); + return VArray<float3>::ForContainer(std::move(tangents)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_tangents = curve_tangent_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_tangents)); - GVArrayPtr spline_tangents = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_tangents)).get(); + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForContainer(std::move(point_tangents)), + ATTR_DOMAIN_POINT, + ATTR_DOMAIN_CURVE); } return nullptr; @@ -126,9 +125,9 @@ class TangentFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -141,7 +140,7 @@ class TangentFieldInput final : public fn::FieldInput { return construct_curve_tangent_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -156,20 +155,22 @@ class TangentFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_tangent_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> tangent_field{std::make_shared<TangentFieldInput>()}; params.set_output("Tangent", std::move(tangent_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_tangent_cc void register_node_type_geo_input_tangent() { + namespace file_ns = blender::nodes::node_geo_input_tangent_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec; - ntype.declare = blender::nodes::geo_node_input_tangent_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index aff29d973d4..d859289fc59 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instance_on_points_cc { -static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -80,10 +80,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, select_len); FieldEvaluator field_evaluator{field_context, domain_size}; - const VArray<bool> *pick_instance = nullptr; - const VArray<int> *indices = nullptr; - const VArray<float3> *rotations = nullptr; - const VArray<float3> *scales = nullptr; + VArray<bool> pick_instance; + VArray<int> indices; + VArray<float3> rotations; + VArray<float3> scales; /* The evaluator could use the component's stable IDs as a destination directly, but only the * selected indices should be copied. */ field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); @@ -92,7 +92,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); field_evaluator.evaluate(); - GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>( + VArray<float3> positions = src_component.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>(); @@ -101,7 +101,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, Array<int> handle_mapping; /* Only fill #handle_mapping when it may be used below. */ if (src_instances != nullptr && - (!pick_instance->is_single() || pick_instance->get_internal_single())) { + (!pick_instance.is_single() || pick_instance.get_internal_single())) { Span<InstanceReference> src_references = src_instances->references(); handle_mapping.reinitialize(src_references.size()); for (const int src_instance_handle : src_references.index_range()) { @@ -121,17 +121,16 @@ static void add_instances_from_component(InstancesComponent &dst_component, /* Compute base transform for every instances. */ float4x4 &dst_transform = dst_transforms[range_i]; - dst_transform = float4x4::from_loc_eul_scale( - positions[i], rotations->get(i), scales->get(i)); + dst_transform = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]); /* Reference that will be used by this new instance. */ int dst_handle = empty_reference_handle; - const bool use_individual_instance = pick_instance->get(i); + const bool use_individual_instance = pick_instance[i]; if (use_individual_instance) { if (src_instances != nullptr) { const int src_instances_amount = src_instances->instances_amount(); - const int original_index = indices->get(i); + const int original_index = indices[i]; /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1 * refers to the last element. */ const int index = mod_i(original_index, std::max(src_instances_amount, 1)); @@ -155,10 +154,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, } }); - GVArrayPtr id_attribute = src_component.attribute_try_get_for_read( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - if (id_attribute) { - GVArray_Typed<int> ids{*id_attribute}; + VArray<int> ids = src_component + .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32) + .typed<int>(); + if (ids) { VArray_Span<int> ids_span{ids}; MutableSpan<int> dst_ids = dst_component.instance_ids_ensure(); for (const int64_t i : selection.index_range()) { @@ -166,8 +165,8 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } - if (pick_instance->is_single()) { - if (pick_instance->get_internal_single()) { + if (pick_instance.is_single()) { + if (pick_instance.get_internal_single()) { if (instance.has_realized_data()) { params.error_message_add( NodeWarningType::Info, @@ -177,7 +176,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } -static void geo_node_instance_on_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); GeometrySet instance = params.get_input<GeometrySet>("Instance"); @@ -215,15 +214,17 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instance_on_points_cc void register_node_type_geo_instance_on_points() { + namespace file_ns = blender::nodes::node_geo_instance_on_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instance_on_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index c3955426e69..71e4a69911c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instances_to_points_cc { -static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -51,9 +51,8 @@ static void convert_instances_to_points(GeometrySet &geometry_set, { const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); - const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; - GeometryComponentFieldContext field_context{instances, attribute_domain}; - const int domain_size = instances.attribute_domain_size(attribute_domain); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(std::move(selection_field)); @@ -88,7 +87,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, } } -static void geo_node_instances_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); @@ -105,15 +104,17 @@ static void geo_node_instances_to_points_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instances_to_points_cc void register_node_type_geo_instances_to_points() { + namespace file_ns = blender::nodes::node_geo_instances_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instances_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc index 8e0e98f7bd5..5925d440317 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc @@ -18,14 +18,14 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_is_viewport_cc { -static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Is Viewport")); } -static void geo_node_is_viewport_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const Depsgraph *depsgraph = params.depsgraph(); const eEvaluationMode mode = DEG_get_mode(depsgraph); @@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params) params.set_output("Is Viewport", is_viewport); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_is_viewport_cc void register_node_type_geo_is_viewport() { + namespace file_ns = blender::nodes::node_geo_is_viewport_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec; - ntype.declare = blender::nodes::geo_node_is_viewport_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 9d363bd1af4..53f7d968644 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -27,11 +27,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; +namespace blender::nodes::node_geo_join_geometry_cc { -namespace blender::nodes { - -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).multi_input(); b.add_output<decl::Geometry>(N_("Geometry")); @@ -190,10 +188,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components, if (domain_size == 0) { continue; } - GVArrayPtr read_attribute = component->attribute_get_for_read( + GVArray read_attribute = component->attribute_get_for_read( attribute_id, domain, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); void *dst_buffer = dst_span[offset]; cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size); @@ -319,8 +317,7 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, spline->size() * type.size(), type.alignment(), __func__); const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type) - ->materialize(converted_buffer); + conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer); spline->attributes.remove(attribute_id); spline->attributes.create_by_move(attribute_id, data_type, converted_buffer); @@ -333,14 +330,14 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, /* In this case the attribute did not exist, but there is a spline domain attribute * we can retrieve a value from, as a spline to point domain conversion. So fill the * new attribute with the value for this spline. */ - GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read( + GVArray current_curve_attribute = current_curve->attributes.get_for_read( attribute_id, data_type, nullptr); BLI_assert(spline->attributes.get_for_read(attribute_id)); std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - current_curve_attribute->get(spline_index_in_component, buffer); + current_curve_attribute.get(spline_index_in_component, buffer); type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size()); } } @@ -397,8 +394,8 @@ static void ensure_spline_attribute(const AttributeIDRef &attribute_id, if (size == 0) { continue; } - GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); type.copy_assign_n(src_buffer, result_attribute[offset], size); @@ -498,7 +495,7 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet join_components(components, result); } -static void geo_node_join_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry"); @@ -511,14 +508,16 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_join_geometry_cc void register_node_type_geo_join_geometry() { + namespace file_ns = blender::nodes::node_geo_join_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec; - ntype.declare = blender::nodes::geo_node_join_geometry_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc index e4a62bd5267..5a334126350 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_replace_cc { -static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Material>(N_("Old")); @@ -34,7 +34,7 @@ static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_material_replace_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *old_material = params.extract_input<Material *>("Old"); Material *new_material = params.extract_input<Material *>("New"); @@ -55,15 +55,17 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_replace_cc void register_node_type_geo_material_replace() { + namespace file_ns = blender::nodes::node_geo_material_replace_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_replace_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 06c770820ee..948565b62f0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_selection_cc { -static void geo_node_material_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Material>(N_("Material")).hide_label(true); b.add_output<decl::Bool>(N_("Selection")).field_source(); @@ -64,36 +64,33 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_MESH) { - return nullptr; + return {}; } const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_FACE) { Array<bool> selection(mask.min_array_size()); select_mesh_by_material(*mesh, material_, mask, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } Array<bool> selection(mesh->totpoly); select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); - GVArrayPtr face_selection = std::make_unique<fn::GVArray_For_ArrayContainer<Array<bool>>>( - std::move(selection)); - GVArrayPtr final_selection = mesh_component.attribute_try_adapt_domain( - std::move(face_selection), ATTR_DOMAIN_FACE, domain); - return scope.add_value(std::move(final_selection)).get(); + return mesh_component.attribute_try_adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); } return nullptr; @@ -114,22 +111,24 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { } }; -static void geo_node_material_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)}; params.set_output("Selection", std::move(material_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_selection_cc void register_node_type_geo_material_selection() { + namespace file_ns = blender::nodes::node_geo_material_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 685a8faff5c..ec06bdc0455 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -25,25 +25,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_circle_cc { -static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Int>(N_("Vertices")) + .default_value(32) + .min(3) + .description(N_("Number of vertices on the circle")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance of the vertices from the origin")); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN( sizeof(NodeGeometryMeshCircle), __func__); @@ -192,7 +197,7 @@ static Mesh *create_circle_mesh(const float radius, return mesh; } -static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage; @@ -215,19 +220,21 @@ static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc void register_node_type_geo_mesh_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 206d48d40c8..d2739e7e3ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -25,53 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { - -static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3).max(512); - b.add_input<decl::Int>(N_("Side Segments")).default_value(1).min(1).max(512); - b.add_input<decl::Int>(N_("Fill Segments")).default_value(1).min(1).max(512); - b.add_input<decl::Float>(N_("Radius Top")).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Radius Bottom")) - .default_value(1.0f) - .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Depth")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_output<decl::Geometry>(N_("Mesh")); -} - -static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node) -{ - NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( - sizeof(NodeGeometryMeshCone), __func__); - - node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; - - node->storage = node_storage; -} +#include <cmath> -static void geo_node_mesh_primitive_cone_update(bNodeTree *UNUSED(ntree), bNode *node) -{ - bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; - bNodeSocket *rings_socket = vertices_socket->next; - bNodeSocket *fill_subdiv_socket = rings_socket->next; - - const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; - const GeometryNodeMeshCircleFillType fill_type = - static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); - const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); -} - -static void geo_node_mesh_primitive_cone_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); -} +namespace blender::nodes { struct ConeConfig { float radius_top; @@ -94,6 +50,8 @@ struct ConeConfig { int tot_edge_rings; int tot_verts; int tot_edges; + int tot_corners; + int tot_faces; /* Helpful vertex indices. */ int first_vert; @@ -107,6 +65,14 @@ struct ConeConfig { int last_fan_edges_start; int last_edge; + /* Helpful face indices. */ + int top_faces_start; + int top_faces_len; + int side_faces_start; + int side_faces_len; + int bottom_faces_start; + int bottom_faces_len; + ConeConfig(float radius_top, float radius_bottom, float depth, @@ -133,6 +99,7 @@ struct ConeConfig { this->tot_edge_rings = this->calculate_total_edge_rings(); this->tot_verts = this->calculate_total_verts(); this->tot_edges = this->calculate_total_edges(); + this->tot_corners = this->calculate_total_corners(); this->first_vert = 0; this->first_ring_verts_start = this->top_has_center_vert ? 1 : first_vert; @@ -144,6 +111,36 @@ struct ConeConfig { this->tot_quad_rings * this->circle_segments * 2; this->last_fan_edges_start = this->tot_edges - this->circle_segments; this->last_edge = this->tot_edges - 1; + + this->top_faces_start = 0; + if (!this->top_is_point) { + this->top_faces_len = (fill_segments - 1) * circle_segments; + this->top_faces_len += this->top_has_center_vert ? circle_segments : 0; + this->top_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0; + } + else { + this->top_faces_len = 0; + } + + this->side_faces_start = this->top_faces_len; + if (this->top_is_point && this->bottom_is_point) { + this->side_faces_len = 0; + } + else { + this->side_faces_len = side_segments * circle_segments; + } + + if (!this->bottom_is_point) { + this->bottom_faces_len = (fill_segments - 1) * circle_segments; + this->bottom_faces_len += this->bottom_has_center_vert ? circle_segments : 0; + this->bottom_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0; + } + else { + this->bottom_faces_len = 0; + } + this->bottom_faces_start = this->side_faces_start + this->side_faces_len; + + this->tot_faces = this->top_faces_len + this->side_faces_len + this->bottom_faces_len; } private: @@ -151,10 +148,7 @@ struct ConeConfig { int calculate_total_edge_rings(); int calculate_total_verts(); int calculate_total_edges(); - - public: - int get_tot_corners() const; - int get_tot_faces() const; + int calculate_total_corners(); }; int ConeConfig::calculate_total_quad_rings() @@ -248,7 +242,7 @@ int ConeConfig::calculate_total_edges() return edge_total; } -int ConeConfig::get_tot_corners() const +int ConeConfig::calculate_total_corners() { if (top_is_point && bottom_is_point) { return 0; @@ -275,32 +269,6 @@ int ConeConfig::get_tot_corners() const return corner_total; } -int ConeConfig::get_tot_faces() const -{ - if (top_is_point && bottom_is_point) { - return 0; - } - - int face_total = 0; - if (top_has_center_vert) { - face_total += circle_segments; - } - else if (!top_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) { - face_total++; - } - - face_total += tot_quad_rings * circle_segments; - - if (bottom_has_center_vert) { - face_total += circle_segments; - } - else if (!bottom_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) { - face_total++; - } - - return face_total; -} - static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeConfig &config) { Array<float2> circle(config.circle_segments); @@ -522,6 +490,60 @@ static void calculate_cone_faces(const MutableSpan<MLoop> &loops, } } +static void calculate_selection_outputs(Mesh *mesh, + const ConeConfig &config, + ConeAttributeOutputs &attribute_outputs) +{ + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + + /* Populate "Top" selection output. */ + if (attribute_outputs.top_id) { + const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + + if (config.top_is_point) { + selection[config.first_vert] = true; + } + else { + selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true); + } + attribute.save(); + } + + /* Populate "Bottom" selection output. */ + if (attribute_outputs.bottom_id) { + const bool face = !config.bottom_is_point && + config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + + if (config.bottom_is_point) { + selection[config.last_vert] = true; + } + else { + selection + .slice(config.bottom_faces_start, + face ? config.bottom_faces_len : config.circle_segments) + .fill(true); + } + attribute.save(); + } + + /* Populate "Side" selection output. */ + if (attribute_outputs.side_id) { + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE); + MutableSpan<bool> selection = attribute.as_span(); + + selection.slice(config.side_faces_start, config.side_faces_len).fill(true); + attribute.save(); + } +} + /** * If the top is the cone tip or has a fill, it is unwrapped into a circle in the * lower left quadrant of the UV. @@ -665,7 +687,8 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, const int circle_segments, const int side_segments, const int fill_segments, - const GeometryNodeMeshCircleFillType fill_type) + const GeometryNodeMeshCircleFillType fill_type, + ConeAttributeOutputs &attribute_outputs) { const ConeConfig config( radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type); @@ -683,7 +706,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, } Mesh *mesh = BKE_mesh_new_nomain( - config.tot_verts, config.tot_edges, 0, config.get_tot_corners(), config.get_tot_faces()); + config.tot_verts, config.tot_edges, 0, config.tot_corners, config.tot_faces); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; @@ -695,67 +718,179 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, calculate_cone_edges(edges, config); calculate_cone_faces(loops, polys, config); calculate_cone_uvs(mesh, config); + calculate_selection_outputs(mesh, config, attribute_outputs); BKE_mesh_normals_tag_dirty(mesh); return mesh; } -static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cone_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Vertices")) + .default_value(32) + .min(3) + .max(512) + .description(N_("Number of points on the circle at the top and bottom")); + b.add_input<decl::Int>(N_("Side Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("The number of edges running vertically along the side of the cone")); + b.add_input<decl::Int>(N_("Fill Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("Number of concentric rings used to fill the round face")); + b.add_input<decl::Float>(N_("Radius Top")) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the top circle of the cone")); + b.add_input<decl::Float>(N_("Radius Bottom")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the bottom circle of the cone")); + b.add_input<decl::Float>(N_("Depth")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Height of the generated cone")); + b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Top")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); +} + +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( + sizeof(NodeGeometryMeshCone), __func__); + + node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; + + node->storage = node_storage; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; + bNodeSocket *rings_socket = vertices_socket->next; + bNodeSocket *fill_subdiv_socket = rings_socket->next; + + const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; + const GeometryNodeMeshCircleFillType fill_type = + static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); + const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); +} + +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage; const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) storage.fill_type; + auto return_default = [&]() { + params.set_output("Top", fn::make_constant_field<bool>(false)); + params.set_output("Bottom", fn::make_constant_field<bool>(false)); + params.set_output("Side", fn::make_constant_field<bool>(false)); + params.set_output("Mesh", GeometrySet()); + }; + const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const float radius_top = params.extract_input<float>("Radius Top"); const float radius_bottom = params.extract_input<float>("Radius Bottom"); const float depth = params.extract_input<float>("Depth"); - Mesh *mesh = create_cylinder_or_cone_mesh( - radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type); + ConeAttributeOutputs attribute_outputs; + if (params.output_is_required("Top")) { + attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection"); + } + if (params.output_is_required("Bottom")) { + attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection"); + } + if (params.output_is_required("Side")) { + attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection"); + } + + Mesh *mesh = create_cylinder_or_cone_mesh(radius_top, + radius_bottom, + depth, + circle_segments, + side_segments, + fill_segments, + fill_type, + attribute_outputs); /* Transform the mesh so that the base of the cone is at the origin. */ BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false); + if (attribute_outputs.top_id) { + params.set_output("Top", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.top_id), params.attribute_producer_name())); + } + if (attribute_outputs.bottom_id) { + params.set_output( + "Bottom", + AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id), + params.attribute_producer_name())); + } + if (attribute_outputs.side_id) { + params.set_output("Side", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.side_id), params.attribute_producer_name())); + } + params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc void register_node_type_geo_mesh_primitive_cone() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cone_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index 3a211993bdc..682efcc81bd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -24,18 +24,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Vector>(N_("Size")) - .default_value(float3(1)) - .min(0.0f) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Int>(N_("Vertices X")).default_value(2).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Y")).default_value(2).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Z")).default_value(2).min(2).max(1000); - b.add_output<decl::Geometry>(N_("Mesh")); -} - struct CuboidConfig { float3 size; int verts_x; @@ -426,6 +414,35 @@ Mesh *create_cuboid_mesh(const float3 size, return mesh; } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cube_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>(N_("Size")) + .default_value(float3(1)) + .min(0.0f) + .subtype(PROP_TRANSLATION) + .description(N_("Side length along each axis")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the X side of the shape")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Y side of the shape")); + b.add_input<decl::Int>(N_("Vertices Z")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Z side of the shape")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + static Mesh *create_cube_mesh(const float3 size, const int verts_x, const int verts_y, @@ -471,7 +488,7 @@ static Mesh *create_cube_mesh(const float3 size, return create_cuboid_mesh(size, verts_x, verts_y, verts_z); } -static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float3 size = params.extract_input<float3>("Size"); const int verts_x = params.extract_input<int>("Vertices X"); @@ -488,14 +505,16 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc void register_node_type_geo_mesh_primitive_cube() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index 3bcf42b40b1..f5ef277de03 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -25,25 +25,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc { -static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Vertices")) .default_value(32) .min(3) .max(512) - .description(N_("The number of vertices around the circumference")); + .description(N_("The number of vertices on the top and bottom circles")); b.add_input<decl::Int>(N_("Side Segments")) .default_value(1) .min(1) .max(512) - .description(N_("The number of segments along the side")); + .description(N_("The number of rectangular segments along each side")); b.add_input<decl::Int>(N_("Fill Segments")) .default_value(1) .min(1) .max(512) - .description(N_("The number of concentric segments of the fill")); + .description(N_("The number of concentric rings used to fill the round faces")); b.add_input<decl::Float>(N_("Radius")) .default_value(1.0f) .min(0.0f) @@ -53,20 +53,21 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) .default_value(2.0f) .min(0.0f) .subtype(PROP_DISTANCE) - .description(N_("The height of the cylinder on the Z axis")); + .description(N_("The height of the cylinder")); b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Top")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); } -static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN( sizeof(NodeGeometryMeshCylinder), __func__); @@ -76,7 +77,7 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod node->storage = node_storage; } -static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *rings_socket = vertices_socket->next; @@ -86,10 +87,10 @@ static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bN const GeometryNodeMeshCircleFillType fill_type = static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); } -static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage; @@ -97,49 +98,89 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) storage.fill_type; + auto return_default = [&]() { + params.set_output("Top", fn::make_constant_field<bool>(false)); + params.set_output("Bottom", fn::make_constant_field<bool>(false)); + params.set_output("Side", fn::make_constant_field<bool>(false)); + params.set_output("Mesh", GeometrySet()); + }; + const float radius = params.extract_input<float>("Radius"); const float depth = params.extract_input<float>("Depth"); const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); + } + + ConeAttributeOutputs attribute_outputs; + if (params.output_is_required("Top")) { + attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection"); + } + if (params.output_is_required("Bottom")) { + attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection"); + } + if (params.output_is_required("Side")) { + attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection"); } /* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */ - Mesh *mesh = create_cylinder_or_cone_mesh( - radius, radius, depth, circle_segments, side_segments, fill_segments, fill_type); + Mesh *mesh = create_cylinder_or_cone_mesh(radius, + radius, + depth, + circle_segments, + side_segments, + fill_segments, + fill_type, + attribute_outputs); + + if (attribute_outputs.top_id) { + params.set_output("Top", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.top_id), params.attribute_producer_name())); + } + if (attribute_outputs.bottom_id) { + params.set_output( + "Bottom", + AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id), + params.attribute_producer_name())); + } + if (attribute_outputs.side_id) { + params.set_output("Side", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.side_id), params.attribute_producer_name())); + } params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc void register_node_type_geo_mesh_primitive_cylinder() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index c4e476981c1..c761380645d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -27,15 +27,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Float>(N_("Size X")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Size Y")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Int>(N_("Vertices X")).default_value(3).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Y")).default_value(3).min(2).max(1000); - b.add_output<decl::Geometry>(N_("Mesh")); -} - static void calculate_uvs( Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y) { @@ -153,7 +144,36 @@ Mesh *create_grid_mesh(const int verts_x, return mesh; } -static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_grid_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Size X")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the X direction")); + b.add_input<decl::Float>(N_("Size Y")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the Y direction")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the X direction")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the Y direction")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + +static void node_geo_exec(GeoNodeExecParams params) { const float size_x = params.extract_input<float>("Size X"); const float size_y = params.extract_input<float>("Size Y"); @@ -171,14 +191,16 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc void register_node_type_geo_mesh_primitive_grid() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index da3dfef3aea..5f483a95063 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -24,12 +24,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc { -static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Int>(N_("Subdivisions")).default_value(1).min(1).max(7); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance from the generated points to the origin")); + b.add_input<decl::Int>(N_("Subdivisions")) + .default_value(1) + .min(1) + .max(7) + .description(N_("Number of subdivisions on top of the basic icosahedron")); b.add_output<decl::Geometry>(N_("Mesh")); } @@ -37,9 +45,10 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) { const float4x4 transform = float4x4::identity(); - const BMeshCreateParams bmcp = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; const BMAllocTemplate allocsize = {0, 0, 0, 0}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, nullptr); BMO_op_callf(bm, @@ -60,7 +69,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) return mesh; } -static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10); const float radius = params.extract_input<float>("Radius"); @@ -69,15 +78,17 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc void register_node_type_geo_mesh_primitive_ico_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index 6515afe5966..cda55eadaf6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -25,22 +25,33 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_line_cc { -static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(10000); - b.add_input<decl::Float>(N_("Resolution")).default_value(1.0f).min(0.1f).subtype(PROP_DISTANCE); - b.add_input<decl::Vector>(N_("Start Location")).subtype(PROP_TRANSLATION); + b.add_input<decl::Int>(N_("Count")) + .default_value(10) + .min(1) + .max(10000) + .description(N_("Number of vertices on the line")); + b.add_input<decl::Float>(N_("Resolution")) + .default_value(1.0f) + .min(0.1f) + .subtype(PROP_DISTANCE) + .description(N_("Length of each individual edge")); + b.add_input<decl::Vector>(N_("Start Location")) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first vertex")); b.add_input<decl::Vector>(N_("Offset")) .default_value({0.0f, 0.0f, 1.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_( + "In offset mode, the distance between each socket on each axis. In end points mode, the " + "position of the final vertex")); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +61,7 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout, } } -static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN( sizeof(NodeGeometryMeshLine), __func__); @@ -61,7 +72,7 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = node_storage; } -static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *resolution_socket = count_socket->next; @@ -77,48 +88,17 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode * (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) ? N_("End Location") : N_("Offset")); - nodeSetSocketAvailability(resolution_socket, + nodeSetSocketAvailability(ntree, + resolution_socket, mode == GEO_NODE_MESH_LINE_MODE_END_POINTS && count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION); - nodeSetSocketAvailability(count_socket, + nodeSetSocketAvailability(ntree, + count_socket, mode == GEO_NODE_MESH_LINE_MODE_OFFSET || count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL); } -static void fill_edge_data(MutableSpan<MEdge> edges) -{ - for (const int i : edges.index_range()) { - edges[i].v1 = i; - edges[i].v2 = i + 1; - edges[i].flag |= ME_LOOSEEDGE; - } -} - -Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) -{ - if (count < 1) { - return nullptr; - } - - Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); - BKE_id_material_eval_ensure_default_slot(&mesh->id); - MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; - MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; - - short normal[3]; - normal_float_to_short_v3(normal, delta.normalized()); - - for (const int i : verts.index_range()) { - copy_v3_v3(verts[i].co, start + delta * i); - copy_v3_v3_short(verts[i].no, normal); - } - - fill_edge_data(edges); - - return mesh; -} - -static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage; const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode; @@ -159,19 +139,58 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } +} // namespace blender::nodes::node_geo_mesh_primitive_line_cc + +namespace blender::nodes { + +static void fill_edge_data(MutableSpan<MEdge> edges) +{ + for (const int i : edges.index_range()) { + edges[i].v1 = i; + edges[i].v2 = i + 1; + edges[i].flag |= ME_LOOSEEDGE; + } +} + +Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) +{ + if (count < 1) { + return nullptr; + } + + Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); + BKE_id_material_eval_ensure_default_slot(&mesh->id); + MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; + MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; + + short normal[3]; + normal_float_to_short_v3(normal, delta.normalized()); + + for (const int i : verts.index_range()) { + copy_v3_v3(verts[i].co, start + delta * i); + copy_v3_v3_short(verts[i].no, normal); + } + + fill_edge_data(edges); + + return mesh; +} + } // namespace blender::nodes void register_node_type_geo_mesh_primitive_line() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare; - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 54a762fc15d..c109596c1c6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -25,13 +25,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc { -static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Segments")).default_value(32).min(3).max(1024); - b.add_input<decl::Int>(N_("Rings")).default_value(16).min(2).max(1024); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Int>(N_("Segments")) + .default_value(32) + .min(3) + .max(1024) + .description(N_("Horizontal resolution of the sphere")); + b.add_input<decl::Int>(N_("Rings")) + .default_value(16) + .min(2) + .max(1024) + .description(N_("The number of horizontal rings")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance from the generated points to the origin")); b.add_output<decl::Geometry>(N_("Mesh")); } @@ -280,7 +292,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const return mesh; } -static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int segments_num = params.extract_input<int>("Segments"); const int rings_num = params.extract_input<int>("Rings"); @@ -301,15 +313,17 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc void register_node_type_geo_mesh_primitive_uv_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index d99c0c851a8..6206b51b6a8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_subdivide_cc { -static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -72,7 +72,7 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev BKE_subdiv_free(subdiv); } -static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -97,14 +97,16 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_subdivide_cc void register_node_type_geo_mesh_subdivide() { + namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index 11865c635b8..90f0af75788 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -18,16 +18,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -56,14 +56,16 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_curve_cc void register_node_type_geo_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 92911e89f59..d3c4aa87547 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -26,9 +26,9 @@ using blender::Array; -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_points_cc { -static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -41,12 +41,12 @@ static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Points")); } -static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN( sizeof(NodeGeometryMeshToPoints), __func__); @@ -113,14 +113,14 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); + GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); OutputAttribute dst = point_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>()); + VArray<T> src_typed = src.typed<T>(); + copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>()); }); dst.save(); } @@ -129,7 +129,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); Field<float3> position = params.extract_input<Field<float3>>("Position"); @@ -172,17 +172,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_points_cc void register_node_type_geo_mesh_to_points() { + namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec; - node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init); - ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index 3ba32c4b674..ff71bf973b2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -21,83 +21,93 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_object_info_cc { -static void geo_node_object_info_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Object>(N_("Object")).hide_label(); b.add_input<decl::Bool>(N_("As Instance")) - .description( - N_("Output the entire object as single instance. " - "This allows instancing non-geometry object types")); + .description(N_("Output the entire object as single instance. " + "This allows instancing non-geometry object types")); b.add_output<decl::Vector>(N_("Location")); b.add_output<decl::Vector>(N_("Rotation")); b.add_output<decl::Vector>(N_("Scale")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_object_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &bnode = params.node(); NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage; const bool transform_space_relative = (node_storage->transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - Object *object = params.get_input<Object *>("Object"); + auto default_transform = [&]() { + params.set_output("Location", float3(0)); + params.set_output("Rotation", float3(0)); + params.set_output("Scale", float3(0)); + }; + auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); }; - float3 location = {0, 0, 0}; - float3 rotation = {0, 0, 0}; - float3 scale = {0, 0, 0}; - GeometrySet geometry_set; + Object *object = params.get_input<Object *>("Object"); const Object *self_object = params.self_object(); + if (object == nullptr) { + default_transform(); + default_geometry(); + return; + } - if (object != nullptr) { - const float4x4 transform = float4x4(self_object->imat) * float4x4(object->obmat); + const float4x4 &object_matrix = object->obmat; + const float4x4 transform = float4x4(self_object->imat) * object_matrix; - float quaternion[4]; - if (transform_space_relative) { - mat4_decompose(location, quaternion, scale, transform.values); - } - else { - mat4_decompose(location, quaternion, scale, object->obmat); + if (transform_space_relative) { + params.set_output("Location", transform.translation()); + params.set_output("Rotation", transform.to_euler()); + params.set_output("Scale", transform.scale()); + } + else { + params.set_output("Location", object_matrix.translation()); + params.set_output("Rotation", object_matrix.to_euler()); + params.set_output("Scale", object_matrix.scale()); + } + + if (params.output_is_required("Geometry")) { + if (object == self_object) { + params.error_message_add(NodeWarningType::Error, + TIP_("Geometry cannot be retrieved from the modifier object")); + default_geometry(); + return; } - quat_to_eul(rotation, quaternion); - - if (object != self_object) { - if (params.get_input<bool>("As Instance")) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(*object); - if (transform_space_relative) { - instances.add_instance(handle, transform); - } - else { - float unit_transform[4][4]; - unit_m4(unit_transform); - instances.add_instance(handle, unit_transform); - } + + GeometrySet geometry_set; + if (params.get_input<bool>("As Instance")) { + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + const int handle = instances.add_reference(*object); + if (transform_space_relative) { + instances.add_instance(handle, transform); } else { - geometry_set = bke::object_get_evaluated_geometry_set(*object); - if (transform_space_relative) { - transform_geometry_set(geometry_set, transform, *params.depsgraph()); - } + instances.add_instance(handle, float4x4::identity()); + } + } + else { + geometry_set = bke::object_get_evaluated_geometry_set(*object); + if (transform_space_relative) { + transform_geometry_set(geometry_set, transform, *params.depsgraph()); } } - } - params.set_output("Location", location); - params.set_output("Rotation", rotation); - params.set_output("Scale", scale); - params.set_output("Geometry", geometry_set); + params.set_output("Geometry", geometry_set); + } } -static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN( sizeof(NodeGeometryObjectInfo), __func__); @@ -105,18 +115,20 @@ static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_object_info_cc void register_node_type_geo_object_info() { + namespace file_ns = blender::nodes::node_geo_object_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0); - node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init); + node_type_init(&ntype, file_ns::node_node_init); node_type_storage( &ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_object_info_layout; - ntype.declare = blender::nodes::geo_node_object_info_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 3e0096824d3..5510773eabd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -21,11 +21,11 @@ #include "node_geometry_util.hh" -using blender::Array; +namespace blender::nodes::node_geo_points_to_vertices_cc { -namespace blender::nodes { +using blender::Array; -static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -74,15 +74,15 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = point_component->attribute_get_for_read( + GVArray src = point_component->attribute_get_for_read( attribute_id, ATTR_DOMAIN_POINT, data_type); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - VArray_Span<T> src_typed_span{*src_typed}; + VArray<T> src_typed = src.typed<T>(); + VArray_Span<T> src_typed_span{src_typed}; copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>()); }); dst.save(); @@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_vertices_cc void register_node_type_geo_points_to_vertices() { + namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_points_to_vertices_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 312ea7df919..a064dca3a3f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -28,9 +28,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); @@ -44,16 +44,14 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Volume")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -61,16 +59,19 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); - nodeSetSocketAvailability( - voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + nodeSetSocketAvailability(ntree, + voxel_size_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); } #ifdef WITH_OPENVDB @@ -165,7 +166,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); Field<float> radius_field = params.get_input<Field<float>>("Radius"); @@ -173,7 +174,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); r_positions.resize(r_positions.size() + domain_size); - positions->materialize(r_positions.as_mutable_span().take_back(domain_size)); + positions.materialize(r_positions.as_mutable_span().take_back(domain_size)); r_radii.resize(r_radii.size() + domain_size); fn::FieldEvaluator evaluator{field_context, domain_size}; @@ -222,22 +223,18 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms, Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr); BKE_volume_init_grids(volume); - VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT); - openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>( - BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false)); - const float density = params.get_input<float>("Density"); convert_to_grid_index_space(voxel_size, positions, radii); openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density); - /* This merge is cheap, because the #density_grid is empty. */ - density_grid->merge(*new_grid); - density_grid->transform().postScale(voxel_size); + new_grid->transform().postScale(voxel_size); + BKE_volume_grid_add_vdb(*volume, "density", std::move(new_grid)); + r_geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES}); r_geometry_set.replace_volume(volume); } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); @@ -253,10 +250,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) #endif } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_volume_cc void register_node_type_geo_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -266,10 +265,10 @@ void register_node_type_geo_points_to_volume() node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); - node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); - ntype.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc index c05476b982b..4431ccd5459 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc @@ -27,9 +27,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_proximity_cc { -static void geo_node_proximity_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) .only_realized_data() @@ -39,7 +39,7 @@ static void geo_node_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Distance")).dependent_field(); } -static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE); } @@ -206,7 +206,7 @@ class ProximityFunction : public fn::MultiFunction { } }; -static void geo_node_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); geometry_set_target.ensure_owns_direct_data(); @@ -233,18 +233,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params) params.set_output("Distance", Field<float>(proximity_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_proximity_cc void register_node_type_geo_proximity() { + namespace file_ns = blender::nodes::node_geo_proximity_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_proximity_init); + node_type_init(&ntype, file_ns::geo_proximity_init); node_type_storage( &ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index 42924a46667..c1f5b0c6706 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -25,11 +25,11 @@ #include "node_geometry_util.hh" -using namespace blender::bke::mesh_surface_sample; +namespace blender::nodes::node_geo_raycast_cc { -namespace blender::nodes { +using namespace blender::bke::mesh_surface_sample; -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target Geometry")) .only_realized_data() @@ -63,13 +63,13 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6}); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -78,7 +78,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); @@ -89,11 +89,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *socket_boolean = socket_color4f->next; bNodeSocket *socket_int32 = socket_boolean->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_vector = (bNodeSocket *)BLI_findlink(&node->outputs, 4); bNodeSocket *out_socket_float = out_socket_vector->next; @@ -101,11 +101,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode) @@ -375,7 +375,7 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet target = params.extract_input<GeometrySet>("Target Geometry"); const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)params.node().storage; @@ -426,20 +426,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_raycast_cc void register_node_type_geo_raycast() { + namespace file_ns = blender::nodes::node_geo_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc index 6c51c1f738f..5b161e66d97 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc @@ -19,30 +19,32 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_realize_instances_cc { -static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_realize_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); geometry_set = bke::geometry_set_realize_instances(geometry_set); params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_realize_instances_cc void register_node_type_geo_realize_instances() { + namespace file_ns = blender::nodes::node_geo_realize_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_realize_instances_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index abf44b1aaf8..0508ff7a215 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_rotate_instances_cc { -static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -32,7 +32,7 @@ static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; const int domain_size = instances_component.instances_amount(); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; @@ -96,7 +96,7 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst }); } -static void geo_node_rotate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -106,15 +106,17 @@ static void geo_node_rotate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_rotate_instances_cc void register_node_type_geo_rotate_instances() { + namespace file_ns = blender::nodes::node_geo_rotate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_rotate_instances_exec; - ntype.declare = blender::nodes::geo_node_rotate_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index ea2b458410e..3e0f3160f89 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_scale_instances_cc { -static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -35,7 +35,7 @@ static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); @@ -75,7 +75,7 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta }); } -static void geo_node_scale_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -85,14 +85,16 @@ static void geo_node_scale_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_scale_instances_cc void register_node_type_geo_scale_instances() { + namespace file_ns = blender::nodes::node_geo_scale_instances_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_scale_instances_exec; - ntype.declare = blender::nodes::geo_node_scale_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc index a16fb712b13..e4adfe6587d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_components_cc { -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Mesh")); @@ -28,7 +28,7 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void geo_node_separate_components_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params) params.set_output("Instances", instances); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_components_cc void register_node_type_geo_separate_components() { + namespace file_ns = blender::nodes::node_geo_separate_components_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_join_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index 28e214c0ccc..220aa07faa6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_geometry_cc { -static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")) @@ -35,14 +35,12 @@ static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) .description(N_("The parts of the geometry not in the selection")); } -static void geo_node_separate_geometry_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } -static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN( sizeof(NodeGeometrySeparateGeometry), __func__); @@ -51,7 +49,7 @@ static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_separate_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -95,10 +93,12 @@ static void geo_node_separate_geometry_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_geometry_cc void register_node_type_geo_separate_geometry() { + namespace file_ns = blender::nodes::node_geo_separate_geometry_cc; + static bNodeType ntype; geo_node_type_base( @@ -109,10 +109,10 @@ void register_node_type_geo_separate_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_separate_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_separate_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_separate_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index b64aa266330..f0b8579ae7d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -21,24 +21,23 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_handles_cc { -static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input<decl::Vector>(N_("Position")).implicit_field(); + b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_set_curve_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN( sizeof(NodeGeometrySetCurveHandlePositions), __func__); @@ -50,7 +49,8 @@ static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node static void set_position_in_component(const GeometryNodeCurveHandleMode mode, GeometryComponent &component, const Field<bool> &selection_field, - const Field<float3> &position_field) + const Field<float3> &position_field, + const Field<float3> &offset_field) { GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); @@ -111,15 +111,26 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } } - OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output_only<float3>( - side, ATTR_DOMAIN_POINT); fn::FieldEvaluator position_evaluator{field_context, &selection}; - position_evaluator.add_with_destination(position_field, positions.varray()); + position_evaluator.add(position_field); + position_evaluator.add(offset_field); position_evaluator.evaluate(); + + const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0); + const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); + + OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( + side, ATTR_DOMAIN_POINT, {0, 0, 0}); + MutableSpan<float3> position_mutable = positions.as_span(); + + for (int i : selection) { + position_mutable[i] = positions_input[i] + offsets_input[i]; + } + positions.save(); } -static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometrySetCurveHandlePositions *node_storage = (NodeGeometrySetCurveHandlePositions *)params.node().storage; @@ -128,6 +139,7 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); Field<float3> position_field = params.extract_input<Field<float3>>("Position"); + Field<float3> offset_field = params.extract_input<Field<float3>>("Offset"); bool has_bezier = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -137,7 +149,8 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) set_position_in_component(mode, geometry_set.get_component_for_write<CurveComponent>(), selection_field, - position_field); + position_field, + offset_field); } }); if (!has_bezier) { @@ -147,22 +160,24 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_handles_cc void register_node_type_geo_set_curve_handles() { + namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_set_curve_handles_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; ntype.minwidth = 100.0f; - node_type_init(&ntype, blender::nodes::geo_node_set_curve_handles_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometrySetCurveHandlePositions", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_set_curve_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index e47ce7dea30..fd486f07e69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_radius_cc { -static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -53,7 +53,7 @@ static void set_radius_in_component(GeometryComponent &component, radii.save(); } -static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -69,15 +69,17 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_radius_cc void register_node_type_geo_set_curve_radius() { + namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_radius_exec; - ntype.declare = blender::nodes::geo_node_set_curve_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index a861c35f738..653ae39b4fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_tilt_cc { -static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_tilt_in_component(GeometryComponent &component, tilts.save(); } -static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,14 +65,16 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_tilt_cc void register_node_type_geo_set_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_set_curve_tilt_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index 77d8e786501..e2f48edc72d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_id_cc { -static void geo_node_set_id_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -63,7 +63,7 @@ static void set_id_in_component(GeometryComponent &component, } } -static void geo_node_set_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,14 +81,16 @@ static void geo_node_set_id_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_id_cc void register_node_type_geo_set_id() { + namespace file_ns = blender::nodes::node_geo_set_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec; - ntype.declare = blender::nodes::geo_node_set_id_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index 3817de02a38..fd65bcc235a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -25,9 +25,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_cc { -static void geo_node_set_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")) .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME}); @@ -59,7 +59,7 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate } } -static void geo_node_set_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -103,14 +103,16 @@ static void geo_node_set_material_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_cc void register_node_type_geo_set_material() { + namespace file_ns = blender::nodes::node_geo_set_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_set_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index a8bb1bd8644..25634311225 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_index_cc { -static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_material_index_in_component(GeometryComponent &component, indices.save(); } -static void geo_node_set_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +64,17 @@ static void geo_node_set_material_index_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_index_cc void register_node_type_geo_set_material_index() { + namespace file_ns = blender::nodes::node_geo_set_material_index_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_index_exec; - ntype.declare = blender::nodes::geo_node_set_material_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index 9ff299542b4..bc7c59f75be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_point_radius_cc { -static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -53,7 +53,7 @@ static void set_radius_in_component(GeometryComponent &component, radii.save(); } -static void geo_node_set_point_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -70,15 +70,17 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_point_radius_cc void register_node_type_geo_set_point_radius() { + namespace file_ns = blender::nodes::node_geo_set_point_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_point_radius_exec; - ntype.declare = blender::nodes::geo_node_set_point_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 4e564386a28..a8e59a807e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_position_cc { -static void geo_node_set_position_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -34,8 +34,11 @@ static void set_position_in_component(GeometryComponent &component, const Field<float3> &position_field, const Field<float3> &offset_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? + ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; + GeometryComponentFieldContext field_context{component, domain}; + const int domain_size = component.attribute_domain_size(domain); if (domain_size == 0) { return; } @@ -57,7 +60,7 @@ static void set_position_in_component(GeometryComponent &component, const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + "position", domain, {0, 0, 0}); MutableSpan<float3> position_mutable = positions.as_span(); for (int i : selection) { @@ -66,7 +69,7 @@ static void set_position_in_component(GeometryComponent &component, positions.save(); } -static void geo_node_set_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -86,14 +89,16 @@ static void geo_node_set_position_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_position_cc void register_node_type_geo_set_position() { + namespace file_ns = blender::nodes::node_geo_set_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec; - ntype.declare = blender::nodes::geo_node_set_position_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 06e25c2ed55..a8831130453 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_shade_smooth_cc { -static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_smooth_in_component(GeometryComponent &component, shades.save(); } -static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +64,17 @@ static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_shade_smooth_cc void register_node_type_geo_set_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_set_shade_smooth_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index ec751ae1d2b..7ffda8787e6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_cyclic_cc { -static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_cyclic_in_component(GeometryComponent &component, cyclics.save(); } -static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,15 +65,17 @@ static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_cyclic_cc void register_node_type_geo_set_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_set_spline_cyclic_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index ccf419975ca..4280372faa6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_resolution_cc { -static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -51,7 +51,7 @@ static void set_resolution_in_component(GeometryComponent &component, resolutions.save(); } -static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,15 +81,17 @@ static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_resolution_cc void register_node_type_geo_set_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_set_spline_resolution_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc index 98d0aca084a..5308b43afb2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc @@ -16,16 +16,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_join_cc { -static void geo_node_string_join_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("Delimiter")); b.add_input<decl::String>(N_("Strings")).multi_input().hide_value(); b.add_output<decl::String>(N_("String")); }; -static void geo_node_string_join_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<std::string> strings = params.extract_multi_input<std::string>("Strings"); const std::string delim = params.extract_input<std::string>("Delimiter"); @@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params) params.set_output("String", std::move(output)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_join_cc void register_node_type_geo_string_join() { + namespace file_ns = blender::nodes::node_geo_string_join_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec; - ntype.declare = blender::nodes::geo_node_string_join_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 95e94a22d81..6a793e12f82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -30,9 +30,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_to_curves_cc { -static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("String")); b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); @@ -60,7 +60,7 @@ static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) b.add_output<decl::String>(N_("Remainder")); } -static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) +static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -79,7 +79,7 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext * uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE); } -static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN( sizeof(NodeGeometryStringToCurves), __func__); @@ -91,17 +91,19 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node node->id = (ID *)BKE_vfont_builtin_get(); } -static void geo_node_string_to_curves_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage; const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode) storage->overflow; bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); + nodeSetSocketAvailability( + ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last; bNodeSocket *width_socket = height_socket->prev; - nodeSetSocketAvailability(height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); + nodeSetSocketAvailability( + ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); node_sock_label(width_socket, overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") : N_("Text Box Width")); @@ -263,7 +265,7 @@ static void add_instances_from_handles(InstancesComponent &instances, }); } -static void geo_node_string_to_curves_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { TextLayout layout = get_text_layout(params); @@ -295,23 +297,25 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params) params.set_output("Curves", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_to_curves_cc void register_node_type_geo_string_to_curves() { + namespace file_ns = blender::nodes::node_geo_string_to_curves_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_string_to_curves_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec; - node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init); - node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_size(&ntype, 190, 120, 700); node_type_storage(&ntype, "NodeGeometryStringToCurves", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 2b3430a5ed0..011d1e2af82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -27,9 +27,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -42,15 +42,13 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE); uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE); } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -59,7 +57,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); #ifndef WITH_OPENSUBDIV @@ -145,18 +143,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_subdivision_surface_cc void register_node_type_geo_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 7e07a552650..3a07af30e19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -26,9 +26,9 @@ #include "FN_multi_function_signature.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_switch_cc { -static void geo_node_switch_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field(); b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false); @@ -83,19 +83,19 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b) b.add_output<decl::Image>(N_("Output"), "Output_011"); } -static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE); } -static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__); data->input_type = SOCK_GEOMETRY; node->storage = data; } -static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeSwitch *node_storage = (NodeSwitch *)node->storage; int index = 0; @@ -110,20 +110,20 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) SOCK_RGBA, SOCK_STRING); - nodeSetSocketAvailability(field_switch, fields_type); - nodeSetSocketAvailability(non_field_switch, !fields_type); + nodeSetSocketAvailability(ntree, field_switch, fields_type); + nodeSetSocketAvailability(ntree, non_field_switch, !fields_type); LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) { if (index <= 1) { continue; } - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } } @@ -232,7 +232,7 @@ template<typename T> void switch_no_fields(GeoNodeExecParams ¶ms, const Stri } } -static void geo_node_switch_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage; const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type); @@ -293,19 +293,21 @@ static void geo_node_switch_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_switch_cc void register_node_type_geo_switch() { + namespace file_ns = blender::nodes::node_geo_switch_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::geo_node_switch_declare; - node_type_init(&ntype, blender::nodes::geo_node_switch_init); - node_type_update(&ntype, blender::nodes::geo_node_switch_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; - ntype.draw_buttons = blender::nodes::geo_node_switch_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index 9754b3f81a0..acd8e6cad25 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -33,17 +33,18 @@ #include "node_geometry_util.hh" +namespace blender::nodes::node_geo_transfer_attribute_cc { + using namespace blender::bke::mesh_surface_sample; using blender::fn::GArray; -namespace blender::nodes { - -static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) - .only_realized_data() - .supported_type( - {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}); + .supported_type({GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}); b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field(); b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field(); @@ -61,9 +62,7 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7}); } -static void geo_node_transfer_attribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { const bNode &node = *static_cast<const bNode *>(ptr->data); const NodeGeometryTransferAttribute &data = *static_cast<const NodeGeometryTransferAttribute *>( @@ -77,7 +76,7 @@ static void geo_node_transfer_attribute_layout(uiLayout *layout, } } -static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN( sizeof(NodeGeometryTransferAttribute), __func__); @@ -86,7 +85,7 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod node->storage = data; } -static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *) node->storage; @@ -103,14 +102,14 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *socket_positions = socket_int32->next; bNodeSocket *socket_indices = socket_positions->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); - nodeSetSocketAvailability(socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); bNodeSocket *out_socket_vector = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_float = out_socket_vector->next; @@ -118,11 +117,11 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data, @@ -541,10 +540,10 @@ class NearestTransferFunction : public fn::MultiFunction { attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) { using T = decltype(dummy); if (use_mesh_ && use_points_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices_and_comparison(*src_mesh, - *src_point, + VArray<T> src_mesh = mesh_data_->typed<T>(); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices_and_comparison(src_mesh, + src_point, mesh_distances, point_distances, mask, @@ -553,12 +552,12 @@ class NearestTransferFunction : public fn::MultiFunction { dst.typed<T>()); } else if (use_points_) { - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices(*src_point, mask, point_indices, dst.typed<T>()); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices(src_point, mask, point_indices, dst.typed<T>()); } else if (use_mesh_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - copy_with_indices(*src_mesh, mask, mesh_indices, dst.typed<T>()); + VArray<T> src_mesh = mesh_data_->typed<T>(); + copy_with_indices(src_mesh, mask, mesh_indices, dst.typed<T>()); } }); } @@ -593,8 +592,10 @@ static const GeometryComponent *find_target_component(const GeometrySet &geometr { /* Choose the other component based on a consistent order, rather than some more complicated * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */ - static const Array<GeometryComponentType> supported_types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}; for (const GeometryComponentType src_type : supported_types) { if (component_is_available(geometry, src_type, domain)) { return geometry.get_component_for_read(src_type); @@ -667,8 +668,7 @@ class IndexTransferFunction : public fn::MultiFunction { attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src{*src_data_}; - copy_with_indices_clamped(*src, mask, indices, dst.typed<T>()); + copy_with_indices_clamped(src_data_->typed<T>(), mask, indices, dst.typed<T>()); }); } }; @@ -720,7 +720,7 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Target"); const bNode &node = params.node(); @@ -738,10 +738,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) }); }; - /* Since the instances are not used, there is no point in keeping - * a reference to them while the field is passed around. */ - geometry.remove(GEO_COMPONENT_TYPE_INSTANCES); - GField output_field; switch (mapping) { case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: { @@ -795,22 +791,24 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) output_attribute_field(params, std::move(output_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_transfer_attribute_cc void register_node_type_geo_transfer_attribute() { + namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_transfer_attribute_init); - node_type_update(&ntype, blender::nodes::geo_node_transfer_attribute_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryTransferAttribute", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_transfer_attribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transfer_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_transfer_attribute_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 2c55a255b5d..8322de20d20 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -35,15 +35,6 @@ namespace blender::nodes { -static void geo_node_transform_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); - b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); - b.add_output<decl::Geometry>(N_("Geometry")); -} - static bool use_translate(const float3 rotation, const float3 scale) { if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) { @@ -69,15 +60,6 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform) BKE_mesh_normals_tag_dirty(&mesh); } -void transform_mesh(Mesh &mesh, - const float3 translation, - const float3 rotation, - const float3 scale) -{ - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - transform_mesh(mesh, matrix); -} - static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); @@ -153,49 +135,71 @@ static void translate_volume(Volume &volume, const float3 translation, const Dep transform_volume(volume, float4x4::from_location(translation), depsgraph); } -void transform_geometry_set(GeometrySet &geometry, - const float4x4 &transform, - const Depsgraph &depsgraph) +static void translate_geometry_set(GeometrySet &geometry, + const float3 translation, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->transform(transform); + curve->translate(translation); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - transform_mesh(*mesh, transform); + translate_mesh(*mesh, translation); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - transform_pointcloud(*pointcloud, transform); + translate_pointcloud(*pointcloud, translation); } if (Volume *volume = geometry.get_volume_for_write()) { - transform_volume(*volume, transform, depsgraph); + translate_volume(*volume, translation, depsgraph); } if (geometry.has_instances()) { - transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); } } -static void translate_geometry_set(GeometrySet &geometry, - const float3 translation, - const Depsgraph &depsgraph) +void transform_geometry_set(GeometrySet &geometry, + const float4x4 &transform, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->translate(translation); + curve->transform(transform); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - translate_mesh(*mesh, translation); + transform_mesh(*mesh, transform); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - translate_pointcloud(*pointcloud, translation); + transform_pointcloud(*pointcloud, transform); } if (Volume *volume = geometry.get_volume_for_write()) { - translate_volume(*volume, translation, depsgraph); + transform_volume(*volume, transform, depsgraph); } if (geometry.has_instances()) { - translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); + transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); } } -static void geo_node_transform_exec(GeoNodeExecParams params) +void transform_mesh(Mesh &mesh, + const float3 translation, + const float3 rotation, + const float3 scale) +{ + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + transform_mesh(mesh, matrix); +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_transform_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); + b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); + b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const float3 translation = params.extract_input<float3>("Translation"); @@ -214,14 +218,16 @@ static void geo_node_transform_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_transform_cc void register_node_type_geo_transform() { + namespace file_ns = blender::nodes::node_geo_transform_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_transform_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index fa05d858a07..8ef80323f99 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_translate_instances_cc { -static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -31,7 +31,7 @@ static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); @@ -60,7 +60,7 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i }); } -static void geo_node_translate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -70,15 +70,17 @@ static void geo_node_translate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_translate_instances_cc void register_node_type_geo_translate_instances() { + namespace file_ns = blender::nodes::node_geo_translate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_translate_instances_exec; - ntype.declare = blender::nodes::geo_node_translate_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index c869846e1f8..f8deaaa4a14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -27,16 +27,16 @@ Mesh *triangulate_mesh(Mesh *mesh, const int flag); } -namespace blender::nodes { +namespace blender::nodes::node_geo_triangulate_cc { -static void geo_node_triangulate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE); uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE); @@ -48,7 +48,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node) node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY; } -static void geo_node_triangulate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4); @@ -69,16 +69,18 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_triangulate_cc void register_node_type_geo_triangulate() { + namespace file_ns = blender::nodes::node_geo_triangulate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_triangulate_declare; - node_type_init(&ntype, blender::nodes::geo_triangulate_init); - ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec; - ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::geo_triangulate_init); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 194d1a751ed..accbcc74174 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -19,8 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { -static void geo_node_viewer_declare(NodeDeclarationBuilder &b) +namespace blender::nodes::node_geo_viewer_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Value")).supports_field().hide_value(); @@ -30,7 +31,7 @@ static void geo_node_viewer_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value(); } -static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer), __func__); @@ -39,7 +40,7 @@ static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } @@ -63,7 +64,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType } } -static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -73,22 +74,24 @@ static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) if (socket->type == SOCK_GEOMETRY) { continue; } - nodeSetSocketAvailability(socket, socket->type == socket_type); + nodeSetSocketAvailability(ntree, socket, socket->type == socket_type); } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_viewer_cc void register_node_type_geo_viewer() { + namespace file_ns = blender::nodes::node_geo_viewer_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0); node_type_storage( &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage); - node_type_update(&ntype, blender::nodes::geo_node_viewer_update); - node_type_init(&ntype, blender::nodes::geo_node_viewer_init); - ntype.declare = blender::nodes::geo_node_viewer_declare; - ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons_ex = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 416d502dc59..12a7435d8be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -35,9 +35,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME); b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE); @@ -47,14 +47,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -62,15 +62,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage; bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); - nodeSetSocketAvailability(voxel_amount_socket, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } @@ -174,7 +176,7 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume"); @@ -192,20 +194,22 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_volume_to_mesh_cc void register_node_type_geo_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..4cba9669647 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -25,12 +25,15 @@ #include "BLT_translation.h" +#include <chrono> + namespace blender::nodes::geometry_nodes_eval_log { using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -63,6 +66,12 @@ ModifierLog::ModifierLog(GeoLogger &logger) node_with_warning.node); node_log.warnings_.append(node_with_warning.warning); } + + for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, + node_with_exec_time.node); + node_log.exec_time_ = node_with_exec_time.exec_time; + } } } @@ -417,25 +426,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); @@ -457,4 +479,9 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str node_warnings_.append({node, {type, std::move(message)}}); } +void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time) +{ + node_exec_times_.append({node, exec_time}); +} + } // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index e5ec50858d9..b80cedc9352 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -251,26 +251,6 @@ void register_node_type_frame(void) /** \name Node Re-Route * \{ */ -/* simple, only a single input and output here */ -static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node) -{ - bNodeLink *link; - - /* Security check! */ - if (!ntree) { - return; - } - - link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "internal node link"); - link->fromnode = node; - link->fromsock = (bNodeSocket *)node->inputs.first; - link->tonode = node; - link->tosock = (bNodeSocket *)node->outputs.first; - /* internal link is always valid */ - link->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, link); -} - static void node_reroute_init(bNodeTree *ntree, bNode *node) { /* NOTE: Cannot use socket templates for this, since it would reset the socket type @@ -288,7 +268,6 @@ void register_node_type_reroute(void) node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0); node_type_init(ntype, node_reroute_init); - node_type_internal_links(ntype, node_reroute_update_internal_links); nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index 8a38b68ec59..e804d10ad75 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -20,16 +20,6 @@ namespace blender::nodes { -void NodeDeclaration::build(bNodeTree &ntree, bNode &node) const -{ - for (const SocketDeclarationPtr &decl : inputs_) { - decl->build(ntree, node, SOCK_IN); - } - for (const SocketDeclarationPtr &decl : outputs_) { - decl->build(ntree, node, SOCK_OUT); - } -} - bool NodeDeclaration::matches(const bNode &node) const { auto check_sockets = [&](ListBase sockets, Span<SocketDeclarationPtr> socket_decls) { diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index c7a3e795c33..f54ef25d4d6 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -39,8 +39,8 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { - const int input_index = provider_->dnode->input_by_identifier(identifier).index(); - const SocketDeclaration &decl = *provider_->dnode->declaration()->inputs()[input_index]; + const SocketDeclaration &decl = + *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration; const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl); if (geo_decl == nullptr) { return; @@ -113,11 +113,11 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const +GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const { const bNodeSocket *found_socket = this->find_available_socket(name); BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ @@ -129,13 +129,13 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, } if (found_socket == nullptr) { - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); /* Try getting the attribute without the default value. */ - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type); + GVArray attribute = component.attribute_try_get_for_read(name, domain, type); if (attribute) { return attribute; } @@ -147,36 +147,36 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, this->error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + name + "\""); } - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } const DataTypeConversions &conversions = get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_INT) { const int value = this->get_input<int>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_VECTOR) { const float3 value = this->get_input<float3>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_RGBA) { const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized( CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } BLI_assert(false); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } CustomDataType GeoNodeExecParams::get_input_attribute_data_type( @@ -288,7 +288,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, BLI_assert_unreachable(); } else if (requested_type != nullptr) { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; @@ -328,7 +328,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType BLI_assert_unreachable(); } else { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 11356178d87..68e8f6421bd 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -51,6 +51,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -269,10 +270,11 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user) return; } if (ntype->declare != nullptr) { - nodeDeclarationEnsure(ntree, node); + nodeDeclarationEnsureOnOutdatedNode(ntree, node); if (!node->declaration->matches(*node)) { refresh_node(*ntree, *node, *node->declaration, do_id_user); } + nodeSocketDeclarationsUpdate(node); return; } /* Don't try to match socket lists when there are no templates. @@ -696,17 +698,15 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<bool>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -714,17 +714,15 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<float>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<float>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -732,17 +730,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<int>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<int>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -750,17 +746,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -768,20 +762,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->get_base_cpp_type = []() { - return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); - }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -789,18 +779,16 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } @@ -814,11 +802,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -826,11 +814,11 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -838,11 +826,11 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -850,11 +838,11 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -862,11 +850,11 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -874,11 +862,11 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index ba0cfeacb83..231030030eb 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -41,6 +41,8 @@ #include "MEM_guardedalloc.h" +#include "NOD_common.h" + #include "node_util.h" /* -------------------------------------------------------------------- */ @@ -97,12 +99,13 @@ void node_sock_label_clear(bNodeSocket *sock) } } -void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) +void node_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0); bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1); bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2); - nodeSetSocketAvailability(sock2, + nodeSetSocketAvailability(ntree, + sock2, !ELEM(node->custom1, NODE_MATH_SQRT, NODE_MATH_SIGN, @@ -126,7 +129,8 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) NODE_MATH_COSH, NODE_MATH_SINH, NODE_MATH_TANH)); - nodeSetSocketAvailability(sock3, + nodeSetSocketAvailability(ntree, + sock3, ELEM(node->custom1, NODE_MATH_COMPARE, NODE_MATH_MULTIPLY_ADD, @@ -491,6 +495,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype /* select a suitable input socket for an output */ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) { + if (node->type == NODE_REROUTE) { + return node->inputs.first; + } + bNodeSocket *selected = NULL, *input; int i; int sel_priority = -1; @@ -524,7 +532,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) return selected; } -void node_update_internal_links_default(bNodeTree *ntree, bNode *node) +void node_internal_links_create(bNodeTree *ntree, bNode *node) { bNodeLink *link; bNodeSocket *output, *input; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 9cbb21e02f7..c064ef4ab36 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -83,7 +83,6 @@ void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, /*** Link Handling */ void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); -void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void node_socket_set_float(struct bNodeTree *ntree, diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc index 1a71a3418a5..d4cd7dc6bfe 100644 --- a/source/blender/nodes/intern/type_conversions.cc +++ b/source/blender/nodes/intern/type_conversions.cc @@ -24,19 +24,16 @@ namespace blender::nodes { -using fn::GVArrayPtr; -using fn::GVMutableArray; -using fn::GVMutableArrayPtr; using fn::MFDataType; template<typename From, typename To, To (*ConversionF)(const From &)> static void add_implicit_conversion(DataTypeConversions &conversions) { - const CPPType &from_type = CPPType::get<From>(); - const CPPType &to_type = CPPType::get<To>(); - const std::string conversion_name = from_type.name() + " to " + to_type.name(); + static const CPPType &from_type = CPPType::get<From>(); + static const CPPType &to_type = CPPType::get<To>(); + static const std::string conversion_name = from_type.name() + " to " + to_type.name(); - static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF}; + static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF}; static auto convert_single_to_initialized = [](const void *src, void *dst) { *(To *)dst = ConversionF(*(const From *)src); }; @@ -242,107 +239,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } -class GVArray_For_ConvertedGVArray : public GVArray { +class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl { private: - GVArrayPtr varray_; + fn::GVArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; public: - GVArray_For_ConvertedGVArray(GVArrayPtr varray, + GVArray_For_ConvertedGVArray(fn::GVArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type()) + : fn::GVArrayImpl(to_type, varray.size()), + varray_(std::move(varray)), + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } }; -class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray { +class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl { private: - GVMutableArrayPtr varray_; + fn::GVMutableArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; ConversionFunctions new_to_old_conversions_; public: - GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray, + GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVMutableArray(to_type, varray->size()), + : fn::GVMutableArrayImpl(to_type, varray.size()), varray_(std::move(varray)), - from_type_(varray_->type()) + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); - varray_->set_by_relocate(index, buffer); + varray_.set_by_relocate(index, buffer); } }; -fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray, - const CPPType &to_type) const +fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); + return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); } -fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray, - const CPPType &to_type) const +fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray, + const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>( + return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>( std::move(varray), to_type, *this); } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 97041b3fdfd..e1f6c135568 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -54,7 +54,6 @@ void sh_node_type_base( ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c index e29b2ee1c5c..d2b40a7ec39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c @@ -59,59 +59,34 @@ static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *no } /* Triggers (in)visibility of some sockets when changing Parametrization. */ -static void node_shader_update_hair_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int parametrization = node->custom1; for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE); } else if (STREQ(sock->name, "Melanin")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Melanin Redness")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Tint")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Absorption Coefficient")) { - if (parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION); } else if (STREQ(sock->name, "Random Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index cb4f0594310..89b7164693f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -167,7 +167,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, sss_scale); } -static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int distribution = node->custom1; @@ -175,21 +175,11 @@ static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Transmission Roughness")) { - if (distribution == SHD_GLOSSY_GGX) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); } if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) { - if (sss_method == SHD_SUBSURFACE_BURLEY) { - sock->flag |= SOCK_UNAVAIL; - } - else { - sock->flag &= ~SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 4df5add7151..a1dac05434e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -237,7 +237,6 @@ void register_node_type_sh_group(void) ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -261,9 +260,6 @@ void register_node_type_sh_custom_group(bNodeType *ntype) if (ntype->insert_link == NULL) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == NULL) { - ntype->update_internal_links = node_update_internal_links_default; - } node_type_exec(ntype, group_initexec, group_freeexec, group_execute); node_type_gpu(ntype, gpu_group_execute); diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index c866a154e8c..e55963eb500 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -41,10 +41,10 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps"); - nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); + nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); } static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index 774e7fed029..cabfecdb6ee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -57,11 +57,11 @@ static int gpu_shader_mapping(GPUMaterial *mat, return 0; } -static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_mapping(bNodeTree *ntree, bNode *node) { bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location"); nodeSetSocketAvailability( - sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); + ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); } void register_node_type_sh_mapping(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 284a5f1189f..1e94148c5c7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -88,7 +88,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), + function}; base_fn = &fn; }); if (base_fn != nullptr) { @@ -97,7 +98,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name, + static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(), function}; base_fn = &fn; }); @@ -108,7 +109,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; base_fn = &fn; }); if (base_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c index 7e7e1b703f1..32765b459ca 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c @@ -64,8 +64,7 @@ void register_node_type_sh_output_aov(void) &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_output_aov); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.c index 722202bafdc..6c4837f3c6f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.c @@ -36,8 +36,7 @@ void register_node_type_sh_output_light(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c index 5b4ebf21f5f..07e253383e2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c @@ -38,8 +38,7 @@ void register_node_type_sh_output_linestyle(void) node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL); node_type_init(&ntype, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index fb0b6e7b263..41932cca6a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -84,8 +84,7 @@ void register_node_type_sh_output_material(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_material); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c index 59c77e0b25c..09eca7f712e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c @@ -52,8 +52,7 @@ void register_node_type_sh_output_world(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_world); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index 81f9cd735eb..e426d9cc49c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -104,7 +104,7 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node) { NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage; @@ -113,12 +113,14 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset"); bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain"); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inOffsetSock, + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, + inOffsetSock, tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && tex->musgrave_type != SHD_MUSGRAVE_FBM); - nodeSetSocketAvailability(inGainSock, + nodeSetSocketAvailability(ntree, + inGainSock, tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); @@ -199,28 +201,28 @@ class MusgraveFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_detail = [&](int param_index) -> const VArray<float> & { + auto get_detail = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Detail"); }; - auto get_dimension = [&](int param_index) -> const VArray<float> & { + auto get_dimension = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Dimension"); }; - auto get_lacunarity = [&](int param_index) -> const VArray<float> & { + auto get_lacunarity = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Lacunarity"); }; - auto get_offset = [&](int param_index) -> const VArray<float> & { + auto get_offset = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Offset"); }; - auto get_gain = [&](int param_index) -> const VArray<float> & { + auto get_gain = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Gain"); }; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index d28095edb96..7dd2695ecf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -76,14 +76,14 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); NodeTexNoise *tex = (NodeTexNoise *)node->storage; - nodeSetSocketAvailability(sockVector, tex->dimensions != 1); - nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c index 5dc11c4df00..5c581528c14 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c @@ -195,12 +195,12 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out); } -static void node_shader_update_sky(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_sky(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); NodeTexSky *tex = (NodeTexSky *)node->storage; - nodeSetSocketAvailability(sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); + nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc index 422268b98c3..1bc3741d27c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -123,7 +123,7 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out, GPU_constant(&metric)); } -static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node) { bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W"); @@ -138,27 +138,31 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage; - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); nodeSetSocketAvailability( + ntree, inExponentSock, tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); - nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); + nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); - nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outColorSock, + nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, + outColorSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outPositionSock, + nodeSetSocketAvailability(ntree, + outPositionSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && tex->dimensions != 1); - nodeSetSocketAvailability(outWSock, + nodeSetSocketAvailability(ntree, + outWSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && (ELEM(tex->dimensions, 1, 4))); - nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); } namespace blender::nodes { @@ -220,22 +224,22 @@ class VoronoiMinowskiFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_exponent = [&](int param_index) -> const VArray<float> & { + auto get_exponent = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Exponent"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -651,19 +655,19 @@ class VoronoiMetricFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -1153,16 +1157,16 @@ class VoronoiEdgeFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 43ee9400551..7b4ff7fec5c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -58,13 +58,13 @@ static int gpu_shader_tex_white_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); - nodeSetSocketAvailability(sockVector, node->custom1 != 1); - nodeSetSocketAvailability(sockW, node->custom1 == 1 || node->custom1 == 4); + nodeSetSocketAvailability(ntree, sockVector, node->custom1 != 1); + nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index ca5aeea9a7d..9b1b2467230 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -119,7 +119,7 @@ static int gpu_shader_vector_math(GPUMaterial *mat, return 0; } -static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2); @@ -128,7 +128,8 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector"); bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value"); - nodeSetSocketAvailability(sockB, + nodeSetSocketAvailability(ntree, + sockB, !ELEM(node->custom1, NODE_VECTOR_MATH_SINE, NODE_VECTOR_MATH_COSINE, @@ -140,19 +141,22 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node NODE_VECTOR_MATH_ABSOLUTE, NODE_VECTOR_MATH_FRACTION, NODE_VECTOR_MATH_NORMALIZE)); - nodeSetSocketAvailability(sockC, + nodeSetSocketAvailability(ntree, + sockC, ELEM(node->custom1, NODE_VECTOR_MATH_WRAP, NODE_VECTOR_MATH_FACEFORWARD, NODE_VECTOR_MATH_MULTIPLY_ADD)); - nodeSetSocketAvailability(sockScale, - ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); - nodeSetSocketAvailability(sockVector, + nodeSetSocketAvailability( + ntree, sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); + nodeSetSocketAvailability(ntree, + sockVector, !ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, NODE_VECTOR_MATH_DOT_PRODUCT)); - nodeSetSocketAvailability(sockValue, + nodeSetSocketAvailability(ntree, + sockValue, ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, @@ -197,8 +201,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -208,7 +212,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -218,7 +222,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -227,8 +231,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -237,8 +241,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -247,7 +251,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -256,7 +261,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 1ab643bc3fa..3c1f1ed8d39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -193,14 +193,16 @@ static void sh_node_vector_rotate_build_multi_function( builder.set_matching_fn(fn); } -static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); - nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); - nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); + nodeSetSocketAvailability(ntree, sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); - nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } void register_node_type_sh_vector_rotate(void) diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index 570b10d6e89..c968d0bae56 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -57,7 +57,6 @@ void tex_node_type_base( ntype->poll = tex_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread) diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 2de64779ea6..868c97e5850 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -166,7 +166,6 @@ void register_node_type_tex_group(void) ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("TextureNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index b24781e032b..9145df0038b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -172,8 +172,7 @@ void register_node_type_tex_output(void) node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting output. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c index c96ff2062cb..18b11b86d6f 100644 --- a/source/blender/nodes/texture/nodes/node_texture_viewer.c +++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c @@ -60,8 +60,7 @@ void register_node_type_tex_viewer(void) node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting viewer node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 9e725730d40..a49c943df94 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -70,14 +70,15 @@ PyDoc_STRVAR(py_blf_size_doc, "font use 0.\n" " :type fontid: int\n" " :arg size: Point size of the font.\n" - " :type size: int\n" + " :type size: float\n" " :arg dpi: dots per inch value to use for drawing.\n" " :type dpi: int\n"); static PyObject *py_blf_size(PyObject *UNUSED(self), PyObject *args) { - int fontid, size, dpi; + int fontid, dpi; + float size; - if (!PyArg_ParseTuple(args, "iii:blf.size", &fontid, &size, &dpi)) { + if (!PyArg_ParseTuple(args, "ifi:blf.size", &fontid, &size, &dpi)) { return NULL; } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 7646109c1b0..3377b2c283e 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -22,9 +22,13 @@ * A script writer should never directly access this module. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_appdir.h" @@ -149,6 +153,52 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec return list; } +PyDoc_STRVAR(bpy_flip_name_doc, + ".. function:: flip_name(name, strip_digits=False)\n" + "\n" + " Flip a name between left/right sides, useful for \n" + " mirroring bone names.\n" + "\n" + " :arg name: Bone name to flip.\n" + " :type name: string\n" + " :arg strip_digits: Whether to remove ``.###`` suffix.\n" + " :type strip_digits: bool\n" + " :return: The flipped name.\n" + " :rtype: string\n"); +static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *name_src = NULL; + Py_ssize_t name_src_len; + bool strip_digits = false; + + static const char *_keywords[] = {"", "strip_digits", NULL}; + static _PyArg_Parser _parser = { + "s#" /* `name` */ + "|$" /* Optional, keyword only arguments. */ + "O&" /* `strip_digits` */ + /* Name to show in the case of an error. */ + ":flip_name", + _keywords, + 0, + }; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &name_src, &name_src_len, PyC_ParseBool, &strip_digits)) { + return NULL; + } + + /* Worst case we gain one extra byte (besides null-terminator) by changing + "Left" to "Right", because only the first appearance of "Left" gets replaced. */ + const size_t size = name_src_len + 2; + char *name_dst = PyMem_MALLOC(size); + const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size); + + PyObject *result = PyUnicode_FromStringAndSize(name_dst, name_dst_len); + + PyMem_FREE(name_dst); + + return result; +} + // PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { @@ -338,6 +388,12 @@ static PyMethodDef meth_bpy_blend_paths = { METH_VARARGS | METH_KEYWORDS, bpy_blend_paths_doc, }; +static PyMethodDef meth_bpy_flip_name = { + "flip_name", + (PyCFunction)bpy_flip_name, + METH_VARARGS | METH_KEYWORDS, + bpy_flip_name_doc, +}; static PyMethodDef meth_bpy_user_resource = { "user_resource", (PyCFunction)bpy_user_resource, @@ -472,6 +528,8 @@ void BPy_init_modules(struct bContext *C) PyModule_AddObject(mod, meth_bpy_unescape_identifier.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL)); + PyModule_AddObject( + mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL)); /* register funcs (bpy_rna.c) */ PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 5ae123f3254..ae42af7cd85 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -81,7 +81,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) const char *context_str = NULL; PyObject *ret; - int context = WM_OP_EXEC_DEFAULT; + wmOperatorCallContext context = WM_OP_EXEC_DEFAULT; /* XXX TODO: work out a better solution for passing on context, * could make a tuple from self and pack the name and Context into it. */ @@ -107,7 +107,9 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) } if (context_str) { - if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) { + int context_int = context; + + if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) { char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, " @@ -117,6 +119,8 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) MEM_freeN(enum_str); return NULL; } + /* Copy back to the properly typed enum. */ + context = context_int; } if (ELEM(context_dict, NULL, Py_None)) { @@ -166,8 +170,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) PyObject *kw = NULL; /* optional args */ PyObject *context_dict = NULL; /* optional args */ - /* note that context is an int, python does the conversion in this case */ - int context = WM_OP_EXEC_DEFAULT; + wmOperatorCallContext context = WM_OP_EXEC_DEFAULT; int is_undo = false; /* XXX TODO: work out a better solution for passing on context, @@ -209,7 +212,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) } if (context_str) { - if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) { + int context_int = context; + + if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) { char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " @@ -219,6 +224,8 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) MEM_freeN(enum_str); return NULL; } + /* Copy back to the properly typed enum. */ + context = context_int; } if (ELEM(context_dict, NULL, Py_None)) { diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 6d384ed9358..13c7d2947cf 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -366,7 +366,7 @@ static PyObject *bpy_prop_deferred_call(BPy_PropDeferred *UNUSED(self), /** * Expose the function in case scripts need to introspect this information - * (not currently used by Blender it's self). + * (not currently used by Blender itself). */ static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UNUSED(closure)) { @@ -377,7 +377,7 @@ static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UN /** * Expose keywords in case scripts need to introspect this information - * (not currently used by Blender it's self). + * (not currently used by Blender itself). */ static PyObject *bpy_prop_deferred_keywords_get(BPy_PropDeferred *self, void *UNUSED(closure)) { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 7b1877f3191..707de1c2581 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7693,7 +7693,7 @@ PyObject *BPY_rna_doc(void) /** * This could be a static variable as we only have one `bpy.types` module, - * it just keeps the data isolated to store in the module it's self. + * it just keeps the data isolated to store in the module itself. * * This data doesn't change one initialized. */ diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index fbbf4bc53ea..f3a64c9cd62 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -33,10 +33,15 @@ struct Scene; struct Sequence; int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); +bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene, + ListBase *seqbase, + struct Sequence *src_seq, + ListBase *dst_seqbase); bool SEQ_edit_move_strip_to_meta(struct Scene *scene, struct Sequence *src_seq, struct Sequence *dst_seqm, const char **error_str); +bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str); void SEQ_edit_flag_for_removal(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq); diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index b9ee23a9186..6a6889c3679 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -2942,6 +2942,9 @@ static ImBuf *do_solid_color(const SeqRenderData *context, } } } + + out->planes = R_IMF_PLANES_RGB; + return out; } @@ -3741,7 +3744,7 @@ static void init_text_effect(Sequence *seq) data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars"); data->text_font = NULL; data->text_blf_id = -1; - data->text_size = 60; + data->text_size = 60.0f; copy_v4_fl(data->color, 1.0f); data->shadow_color[3] = 0.7f; @@ -3842,7 +3845,7 @@ static int num_inputs_text(void) static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) { TextVars *data = seq->effectdata; - if (data->text[0] == 0 || data->text_size < 1 || + if (data->text[0] == 0 || data->text_size < 1.0f || ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) { return EARLY_USE_INPUT_1; @@ -4024,6 +4027,14 @@ static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) return EARLY_DO_EFFECT; } +static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1) +{ + if (facf0 == 0.0f && facf1 == 0.0f) { + return EARLY_USE_INPUT_2; + } + return EARLY_DO_EFFECT; +} + static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *facf0, @@ -4134,6 +4145,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.multithreaded = true; rval.init = init_alpha_over_or_under; rval.execute_slice = do_alphaover_effect; + rval.early_out = early_out_mul_input1; break; case SEQ_TYPE_OVERDROP: rval.multithreaded = true; diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 8ce3398024d..6030b49537c 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -466,6 +466,45 @@ static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out) IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST); } +/* Check whether transform introduces transparent ares in the result (happens when the transformed + * image does not fully cover the render frame). + * + * The check is done by checking whether all corners of viewport fit inside of the transformed + * image. If they do not the image will have transparent areas. */ +static bool seq_image_transform_transparency_gained(const SeqRenderData *context, Sequence *seq) +{ + Scene *scene = context->scene; + const int x = context->rectx; + const int y = context->recty; + + float seq_image_quad[4][2]; + SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad); + for (int i = 0; i < 4; i++) { + add_v2_v2(seq_image_quad[i], (float[]){x / 2, y / 2}); + } + + return !isect_point_quad_v2((float[]){x, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){x, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]); +} + static void sequencer_preprocess_transform_crop( ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image) { @@ -490,6 +529,13 @@ static void sequencer_preprocess_transform_crop( const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR : IMB_FILTER_NEAREST; IMB_transform(in, out, transform_matrix, &source_crop, filter); + + if (!seq_image_transform_transparency_gained(context, seq)) { + out->planes = in->planes; + } + else { + out->planes = R_IMF_PLANES_RGBA; + } } static void multibuf(ImBuf *ibuf, const float fmul) @@ -525,6 +571,10 @@ static void multibuf(ImBuf *ibuf, const float fmul) rt_float += 4; } } + + if (ELEM(ibuf->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB) && fmul < 1.0f) { + ibuf->planes = R_IMF_PLANES_RGBA; + } } static ImBuf *input_preprocess(const SeqRenderData *context, @@ -1804,6 +1854,20 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, early_out = seq_get_early_out_for_blend_mode(seq); + /* Early out for alpha over. It requires image to be rendered, so it can't use + * `seq_get_early_out_for_blend_mode`. */ + if (out == NULL && seq->blend_mode == SEQ_TYPE_ALPHAOVER && seq->blend_opacity == 100.0f) { + ImBuf *test = seq_render_strip(context, state, seq, timeline_frame); + if (ELEM(test->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB)) { + early_out = EARLY_USE_INPUT_2; + } + else { + early_out = EARLY_DO_EFFECT; + } + /* Free the image. It is stored in cache, so this doesn't affect performance. */ + IMB_freeImBuf(test); + } + switch (early_out) { case EARLY_NO_INPUT: case EARLY_USE_INPUT_2: @@ -1828,6 +1892,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, } break; } + if (out) { break; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 70ac2620e20..382fdd4953f 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -159,7 +159,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->scene = load_data->scene; seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); @@ -180,7 +180,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->clip = load_data->clip; seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); @@ -201,7 +201,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->mask = load_data->mask; seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); @@ -230,18 +230,12 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa seq->seq2 = load_data->effect.seq2; seq->seq3 = load_data->effect.seq3; - if (seq->type == SEQ_TYPE_COLOR) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_ADJUSTMENT) { - seq->blend_mode = SEQ_TYPE_CROSS; + if (SEQ_effect_get_num_inputs(seq->type) == 1) { + seq->blend_mode = seq->seq1->blend_mode; } - else if (seq->type == SEQ_TYPE_TEXT) { + else { seq->blend_mode = SEQ_TYPE_ALPHAOVER; } - else if (SEQ_effect_get_num_inputs(seq->type) == 1) { - seq->blend_mode = seq->seq1->blend_mode; - } if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ @@ -326,7 +320,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ seq->len = load_data->image.len; Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); @@ -587,7 +581,7 @@ Sequence *SEQ_add_movie_strip( } } - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 747f0eb3deb..00b3da86306 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -221,6 +221,40 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase) return false; } +/** + * Move sequence to seqbase. + * + * \param scene: Scene containing the editing + * \param dst_seqbase: seqbase where `seq` is located + * \param seq: Sequence to move + * \param dst_seqbase: Target seqbase + */ +bool SEQ_edit_move_strip_to_seqbase(Scene *scene, + ListBase *seqbase, + Sequence *seq, + ListBase *dst_seqbase) +{ + /* Move to meta. */ + BLI_remlink(seqbase, seq); + BLI_addtail(dst_seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + + /* Update meta. */ + if (SEQ_transform_test_overlap(dst_seqbase, seq)) { + SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene); + } + + return true; +} + +/** + * Move sequence to meta sequence. + * + * \param scene: Scene containing the editing + * \param src_seq: Sequence to move + * \param dst_seqm: Target Meta sequence + * \param error_str: Error message + */ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *src_seq, Sequence *dst_seqm, @@ -262,17 +296,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, collection) { /* Move to meta. */ - BLI_remlink(seqbase, seq); - BLI_addtail(&dst_seqm->seqbase, seq); - SEQ_relations_invalidate_cache_preprocessed(scene, seq); - - /* Update meta. */ - ListBase *meta_seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, dst_seqm); - SEQ_time_update_meta_strip_range(scene, dst_seqm); - SEQ_time_update_sequence(scene, meta_seqbase, dst_seqm); - if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) { - SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene); - } + SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase); } SEQ_collection_free(collection); diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index becf44a7a8e..63ab4a30edc 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -520,10 +520,11 @@ static void seq_image_transform_quad_get_ex(const Scene *scene, } /** - * Get 4 corner points of strip image, optionally without rotation component applied + * Get 4 corner points of strip image, optionally without rotation component applied. + * Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param apply_rotation: Apply sequence rotation transform to the quad * \param r_quad: array of 4 2D vectors */ @@ -536,10 +537,10 @@ void SEQ_image_transform_quad_get(const Scene *scene, } /** - * Get 4 corner points of strip image. + * Get 4 corner points of strip image. Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param r_quad: array of 4 2D vectors */ void SEQ_image_transform_final_quad_get(const Scene *scene, diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ef81addbb4d..c41c328c006 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -413,7 +413,7 @@ int WM_generic_select_invoke(struct bContext *C, const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); -int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); +int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext); int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); void WM_menu_name_call(struct bContext *C, const char *menu_name, short context); int WM_enum_search_invoke_previews(struct bContext *C, @@ -451,7 +451,7 @@ int WM_operator_confirm_message_ex(struct bContext *C, const char *title, const int icon, const char *message, - const short opcontext); + const wmOperatorCallContext opcontext); int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message); /* operator api */ @@ -474,26 +474,26 @@ bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op bool WM_operator_name_poll(struct bContext *C, const char *opstring); int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, - short context, + wmOperatorCallContext context, struct PointerRNA *properties); int WM_operator_name_call(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct PointerRNA *properties); int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct IDProperty *properties); int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, - short context, + wmOperatorCallContext context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo); void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C, wmOperatorType *ot, - short opcontext, + wmOperatorCallContext opcontext, PointerRNA *properties, const char *drawstr); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 564afe084b9..0633ffe55ea 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -26,6 +26,7 @@ /* dna-savable wmStructs here */ #include "BLI_utildefines.h" #include "DNA_windowmanager_types.h" +#include "WM_types.h" #ifdef __cplusplus extern "C" { @@ -169,14 +170,14 @@ int WM_keymap_item_raw_to_string(const short shift, const int result_len); wmKeyMapItem *WM_key_event_operator(const struct bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, struct IDProperty *properties, const short include_mask, const short exclude_mask, struct wmKeyMap **r_keymap); char *WM_key_event_operator_string(const struct bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, struct IDProperty *properties, const bool is_strict, char *result, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 27c8aa532f2..b8fe3786bde 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -211,7 +211,7 @@ enum { * Context to call operator in for #WM_operator_name_call. * rna_ui.c contains EnumPropertyItem's of these, keep in sync. */ -enum { +typedef enum wmOperatorCallContext { /* if there's invoke, call it, otherwise exec */ WM_OP_INVOKE_DEFAULT, WM_OP_INVOKE_REGION_WIN, @@ -226,9 +226,11 @@ enum { WM_OP_EXEC_REGION_PREVIEW, WM_OP_EXEC_AREA, WM_OP_EXEC_SCREEN, -}; +} wmOperatorCallContext; -#define WM_OP_CONTEXT_HAS_AREA(type) (!ELEM(type, WM_OP_INVOKE_SCREEN, WM_OP_EXEC_SCREEN)) +#define WM_OP_CONTEXT_HAS_AREA(type) \ + (CHECK_TYPE_INLINE(type, wmOperatorCallContext), \ + !ELEM(type, WM_OP_INVOKE_SCREEN, WM_OP_EXEC_SCREEN)) #define WM_OP_CONTEXT_HAS_REGION(type) \ (WM_OP_CONTEXT_HAS_AREA(type) && !ELEM(type, WM_OP_INVOKE_AREA, WM_OP_EXEC_AREA)) @@ -923,7 +925,7 @@ typedef struct wmOperatorType { typedef struct wmOperatorCallParams { struct wmOperatorType *optype; struct PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; } wmOperatorCallParams; #ifdef WITH_INPUT_IME @@ -1079,6 +1081,10 @@ typedef struct wmDrag { /** * Dropboxes are like keymaps, part of the screen/area/region definition. * Allocation and free is on startup and exit. + * + * The operator is polled and invoked with the current context (#WM_OP_INVOKE_DEFAULT), there is no + * way to override that (by design, since dropboxes should act on the exact mouse position). So the + * drop-boxes are supposed to check the required area and region context in their poll. */ typedef struct wmDropBox { struct wmDropBox *next, *prev; @@ -1120,10 +1126,6 @@ typedef struct wmDropBox { struct IDProperty *properties; /** RNA pointer to access properties. */ struct PointerRNA *ptr; - - /** Default invoke. */ - short opcontext; - } wmDropBox; /** diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index ceaec94e70b..8bf82a41c91 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -29,6 +29,7 @@ #pragma once #include "BLI_compiler_attrs.h" +#include "BLI_utildefines.h" struct wmGizmo; struct wmGizmoGroup; @@ -163,6 +164,8 @@ typedef enum eWM_GizmoFlagGroupTypeFlag { WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 10), } eWM_GizmoFlagGroupTypeFlag; +ENUM_OPERATORS(eWM_GizmoFlagGroupTypeFlag, WM_GIZMOGROUPTYPE_VR_REDRAWS); + /** * #wmGizmoGroup.init_flag */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 4458b386ab6..47ee296823b 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -91,13 +91,18 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) /* This pointer can be NULL during old files reading, better be safe than sorry. */ if (win->workspace_hook != NULL) { ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); - BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP); + BKE_lib_query_foreachid_process(data, &workspace, IDWALK_CB_USER); /* Allow callback to set a different workspace. */ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; + } } + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { - BKE_screen_foreach_id_screen_area(data, area); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_screen_foreach_id_screen_area(data, area)); } } } diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 49b84abf9a2..bc87347b2f3 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -122,7 +122,6 @@ wmDropBox *WM_dropbox_add(ListBase *lb, drop->cancel = cancel; drop->tooltip = tooltip; drop->ot = WM_operatortype_find(idname, 0); - drop->opcontext = WM_OP_INVOKE_DEFAULT; if (drop->ot == NULL) { MEM_freeN(drop); @@ -324,7 +323,8 @@ static wmDropBox *dropbox_active(bContext *C, continue; } - if (WM_operator_poll_context(C, drop->ot, drop->opcontext)) { + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); + if (WM_operator_poll_context(C, drop->ot, opcontext)) { return drop; } @@ -392,10 +392,11 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) { + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); /* Optionally copy drag information to operator properties. Don't call it if the * operator fails anyway, it might do more than just set properties (e.g. * typically import an asset). */ - if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) { + if (drop->copy && WM_operator_poll_context(C, drop->ot, opcontext)) { drop->copy(drag, drop); } @@ -423,6 +424,16 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event) } } +/** + * The operator of a dropbox should always be executed in the context determined by the mouse + * coordinates. The dropbox poll should check the context area and region as needed. + * So this always returns #WM_OP_INVOKE_DEFAULT. + */ +wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop)) +{ + return WM_OP_INVOKE_DEFAULT; +} + /* ************** IDs ***************** */ void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 8acce240046..d8d57a9370c 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -108,6 +108,8 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) } if (pc->poll == NULL || pc->poll(C)) { + UI_SetTheme(area->spacetype, region->regiontype); + /* Prevent drawing outside region. */ GPU_scissor_test(true); GPU_scissor(region->winrct.xmin, @@ -839,6 +841,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) } /* After area regions so we can do area 'overlay' drawing. */ + UI_SetTheme(0, 0); ED_screen_draw_edges(win); wm_draw_callbacks(win); wmWindowViewport(win); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b780fef289a..474d900a53d 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -108,7 +108,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, + const wmOperatorCallContext context, const bool poll_only, wmEvent *event); @@ -1460,7 +1460,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, + const wmOperatorCallContext context, const bool poll_only, wmEvent *event) { @@ -1595,13 +1595,16 @@ static int wm_operator_call_internal(bContext *C, /* Invokes operator in context. */ int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, - short context, + wmOperatorCallContext context, PointerRNA *properties) { BLI_assert(ot == WM_operatortype_find(ot->idname, true)); return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL); } -int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties) +int WM_operator_name_call(bContext *C, + const char *opstring, + wmOperatorCallContext context, + PointerRNA *properties) { wmOperatorType *ot = WM_operatortype_find(opstring, 0); if (ot) { @@ -1623,7 +1626,7 @@ bool WM_operator_name_poll(bContext *C, const char *opstring) int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct IDProperty *properties) { PointerRNA props_ptr; @@ -1654,7 +1657,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context) */ int WM_operator_call_py(bContext *C, wmOperatorType *ot, - short context, + wmOperatorCallContext context, PointerRNA *properties, ReportList *reports, const bool is_undo) @@ -1778,8 +1781,11 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us return WM_UI_HANDLER_CONTINUE; } -void WM_operator_name_call_ptr_with_depends_on_cursor( - bContext *C, wmOperatorType *ot, short opcontext, PointerRNA *properties, const char *drawstr) +void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, + wmOperatorType *ot, + wmOperatorCallContext opcontext, + PointerRNA *properties, + const char *drawstr) { int flag = ot->flag; @@ -3073,8 +3079,9 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis BLI_addtail(&single_lb, drag); event->customdata = &single_lb; + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); int op_retval = wm_operator_call_internal( - C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event); + C, drop->ot, drop->ptr, NULL, opcontext, false, event); OPERATOR_RETVAL_CHECK(op_retval); if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) { diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index b45cf765a75..00ac1c2ffe6 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -53,6 +53,7 @@ #include "BLO_readfile.h" #include "BKE_armature.h" +#include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_key.h" @@ -166,838 +167,6 @@ static int wm_link_append_flag(wmOperator *op) return flag; } -typedef struct WMLinkAppendDataItem { - char *name; - BLI_bitmap - *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ - short idcode; - - /** Type of action to do to append this item, and other append-specific information. */ - char append_action; - char append_tag; - - ID *new_id; - Library *source_library; - void *customdata; -} WMLinkAppendDataItem; - -typedef struct WMLinkAppendData { - LinkNodePair libraries; - LinkNodePair items; - int num_libraries; - int num_items; - /** - * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h - */ - int flag; - - /** Allows to easily find an existing items from an ID pointer. Used by append code. */ - GHash *new_id_to_item; - - /** Runtime info used by append code to manage re-use of already appended matching IDs. */ - GHash *library_weak_reference_mapping; - - /* Internal 'private' data */ - MemArena *memarena; -} WMLinkAppendData; - -typedef struct WMLinkAppendDataCallBack { - WMLinkAppendData *lapp_data; - WMLinkAppendDataItem *item; - ReportList *reports; - -} WMLinkAppendDataCallBack; - -enum { - WM_APPEND_ACT_UNSET = 0, - WM_APPEND_ACT_KEEP_LINKED, - WM_APPEND_ACT_REUSE_LOCAL, - WM_APPEND_ACT_MAKE_LOCAL, - WM_APPEND_ACT_COPY_LOCAL, -}; - -enum { - WM_APPEND_TAG_INDIRECT = 1 << 0, -}; - -static WMLinkAppendData *wm_link_append_data_new(const int flag) -{ - MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - - lapp_data->flag = flag; - lapp_data->memarena = ma; - - return lapp_data; -} - -static void wm_link_append_data_free(WMLinkAppendData *lapp_data) -{ - if (lapp_data->new_id_to_item != NULL) { - BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); - } - - BLI_assert(lapp_data->library_weak_reference_mapping == NULL); - - BLI_memarena_free(lapp_data->memarena); -} - -/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ - -static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) -{ - size_t len = strlen(libname) + 1; - char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - - BLI_strncpy(libpath, libname, len); - BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); - lapp_data->num_libraries++; -} - -static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data, - const char *idname, - const short idcode, - void *customdata) -{ - WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item)); - size_t len = strlen(idname) + 1; - - item->name = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(item->name, idname, len); - item->idcode = idcode; - item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - - item->new_id = NULL; - item->append_action = WM_APPEND_ACT_UNSET; - item->customdata = customdata; - - BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); - lapp_data->num_items++; - - return item; -} - -/* -------------------------------------------------------------------- */ -/** \name Library appending helper functions. - * - * FIXME: Deduplicate code with similar one in readfile.c - * \{ */ - -static bool object_in_any_scene(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { - if (BKE_scene_object_find(sce, ob)) { - return true; - } - } - - return false; -} - -static bool object_in_any_collection(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - return true; - } - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (scene->master_collection != NULL && - BKE_collection_has_object(scene->master_collection, ob)) { - return true; - } - } - - return false; -} - -static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item) -{ - /* We consider that if we either kept it linked, or re-used already local data, instantiation - * status of those should not be modified. */ - if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) { - return NULL; - } - - ID *id = item->new_id; - if (id == NULL) { - return NULL; - } - - if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - return NULL; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; -} - -static void wm_append_loose_data_instantiate_ensure_active_collection( - WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - Collection **r_active_collection) -{ - /* Find or add collection as needed. */ - if (*r_active_collection == NULL) { - if (lapp_data->flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - *r_active_collection = lc->collection; - } - else { - *r_active_collection = BKE_collection_add(bmain, scene->master_collection, NULL); - } - } -} - -/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that - * in BKE. */ -static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - if (scene == NULL) { - /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. - */ - return; - } - - LinkNode *itemlink; - Collection *active_collection = NULL; - const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; - - /* Do NOT make base active here! screws up GUI stuff, - * if you want it do it at the editor level. */ - const bool object_set_active = false; - - /* First pass on obdata to enable their instantiation by default, then do a second pass on - * objects to clear it for any obdata already in use. */ - if (do_obdata) { - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - - id->tag |= LIB_TAG_DOIT; - } - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - Object *new_ob = (Object *)id->newid; - if (ob->data != NULL) { - ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; - } - if (new_ob != NULL && new_ob->data != NULL) { - ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; - } - } - } - - /* First do collections, then objects, then obdata. */ - - /* NOTE: For collections we only view_layer-instantiate duplicated collections that have - * non-instantiated objects in them. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_GR) { - continue; - } - - /* We do not want to force instantiation of indirectly appended collections. Users can now - * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ - /* We need to check that objects in that collections are already instantiated in a scene. - * Otherwise, it's better to add the collection to the scene's active collection, than to - * instantiate its objects in active scene's collection directly. See T61141. - * - * NOTE: We only check object directly into that collection, not recursively into its - * children. - */ - Collection *collection = (Collection *)id; - /* We always add collections directly selected by the user. */ - bool do_add_collection = (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0; - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - if (!object_in_any_scene(bmain, ob)) { - do_add_collection = true; - break; - } - } - if (do_add_collection) { - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - /* In case user requested instantiation of collections as empties, we do so for the one they - * explicitly selected (originally directly linked IDs). */ - if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && - (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) { - /* BKE_object_add(...) messes with the selection. */ - Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); - ob->type = OB_EMPTY; - ob->empty_drawsize = U.collection_instance_empty_size; - - const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0; - /* TODO: why is it OK to make this active here but not in other situations? - * See other callers of #object_base_instance_init */ - const bool set_active = set_selected; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, set_active); - - /* Assign the collection. */ - ob->instance_collection = collection; - id_us_plus(&collection->id); - ob->transflag |= OB_DUPLICOLLECTION; - copy_v3_v3(ob->loc, scene->cursor.location); - } - else { - /* Add collection as child of active collection. */ - BKE_collection_child_add(bmain, active_collection, collection); - - if ((lapp_data->flag & FILE_AUTOSELECT) != 0) { - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - } - } - } - } - } - } - - /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used - * anywhere. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - - if (object_in_any_collection(bmain, ob)) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - CLAMP_MIN(ob->id.us, 0); - ob->mode = OB_MODE_OBJECT; - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - } - - if (!do_obdata) { - return; - } - - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - if ((id->tag & LIB_TAG_DOIT) == 0) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - const int type = BKE_object_obdata_to_type(id); - BLI_assert(type != -1); - Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); - ob->data = id; - id_us_plus(id); - BKE_object_materials_test(bmain, ob, ob->data); - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - - copy_v3_v3(ob->loc, scene->cursor.location); - - id->tag &= ~LIB_TAG_DOIT; - } - - /* Finally, add rigid body objects and constraints to current RB world(s). */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - BKE_rigidbody_ensure_local_object(bmain, (Object *)id); - } -} - -/** \} */ - -static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data) -{ - /* NOTE: It is important to also skip liboverride references here, as those should never be made - * local. */ - if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | - IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - return IDWALK_RET_NOP; - } - - WMLinkAppendDataCallBack *data = cb_data->user_data; - ID *id = *cb_data->id_pointer; - - if (id == NULL) { - return IDWALK_RET_NOP; - } - - if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { - /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, - * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be - * processed, so we need to recursively deal with them here. */ - /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it - * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of - * shapekey referencing the shapekey itself). */ - if (id != cb_data->id_self) { - BKE_library_foreach_ID_link( - cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP); - } - return IDWALK_RET_NOP; - } - - const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0; - if (!do_recursive && cb_data->id_owner->lib != id->lib) { - /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the - * initially directly linked ones. */ - return IDWALK_RET_NOP; - } - - WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id); - if (item == NULL) { - item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL); - item->new_id = id; - item->source_library = id->lib; - /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, - * it was rather linked indirectly. This info is important for instantiation of collections. */ - item->append_tag |= WM_APPEND_TAG_INDIRECT; - BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item); - } - - /* NOTE: currently there is no need to do anything else here, but in the future this would be - * the place to add specific per-usage decisions on how to append an ID. */ - - return IDWALK_RET_NOP; -} - -/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, - * made local, duplicated as local, re-used from local etc. - * - * TODO: Expose somehow this logic to the two other parts of code performing actual append - * (i.e. copy/paste and `bpy` link/append API). - * Then we can heavily simplify #BKE_library_make_local(). */ -static void wm_append_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - BLI_assert((lapp_data->flag & FILE_LINK) == 0); - - const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; - const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; - - const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | - ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != - 0 ? - LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : - 0); - - LinkNode *itemlink; - - /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as - * liboverride references as already existing. */ - lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_ghash_insert(lapp_data->new_id_to_item, id, item); - - /* This ensures that if a liboverride reference is also linked/used by some other appended - * data, it gets a local copy instead of being made directly local, so that the liboverride - * references remain valid (i.e. linked data). */ - if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { - id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; - } - } - - lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); - - /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect - * dependencies), this list will grow and we will process those IDs later, leading to a flatten - * recursive processing of all the linked dependencies. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(item->customdata == NULL); - - /* In Append case linked IDs should never be marked as needing post-processing (instantiation - * of loose objects etc.). */ - BLI_assert((id->tag & LIB_TAG_DOIT) == 0); - - ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? - BKE_main_library_weak_reference_search_item( - lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name) : - NULL; - - if (item->append_action != WM_APPEND_ACT_UNSET) { - /* Already set, pass. */ - } - if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); - item->append_action = WM_APPEND_ACT_KEEP_LINKED; - } - else if (do_reuse_local_id && existing_local_id != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); - item->append_action = WM_APPEND_ACT_REUSE_LOCAL; - item->customdata = existing_local_id; - } - else if (id->tag & LIB_TAG_PRE_EXISTING) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); - item->append_action = WM_APPEND_ACT_COPY_LOCAL; - } - else { - CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); - item->append_action = WM_APPEND_ACT_MAKE_LOCAL; - } - - /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. - */ - if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - WMLinkAppendDataCallBack cb_data = { - .lapp_data = lapp_data, .item = item, .reports = reports}; - BKE_library_foreach_ID_link( - bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP); - } - - /* If we found a matching existing local id but are not re-using it, we need to properly clear - * its weak reference to linked data. */ - if (existing_local_id != NULL && - !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name, - existing_local_id); - } - } - - /* Effectively perform required operation on every linked ID. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - - ID *local_appended_new_id = NULL; - char lib_filepath[FILE_MAX]; - BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); - char lib_id_name[MAX_ID_NAME]; - BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); - - switch (item->append_action) { - case WM_APPEND_ACT_COPY_LOCAL: - BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); - local_appended_new_id = id->newid; - break; - case WM_APPEND_ACT_MAKE_LOCAL: - BKE_lib_id_make_local(bmain, - id, - make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | - LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); - BLI_assert(id->newid == NULL); - local_appended_new_id = id; - break; - case WM_APPEND_ACT_KEEP_LINKED: - /* Nothing to do here. */ - break; - case WM_APPEND_ACT_REUSE_LOCAL: - /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ - ID_NEW_SET(id, item->customdata); - /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ - break; - case WM_APPEND_ACT_UNSET: - CLOG_ERROR( - &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); - break; - default: - BLI_assert(0); - } - - if (local_appended_new_id != NULL) { - if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { - BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping, - lib_filepath, - lib_id_name, - local_appended_new_id); - } - - if (set_fakeuser) { - if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { - /* Do not set fake user on objects nor collections (instancing). */ - id_fake_user_set(local_appended_new_id); - } - } - } - } - - BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping); - lapp_data->library_weak_reference_mapping = NULL; - - /* Remap IDs as needed. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - continue; - } - } - - BLI_assert(!ID_IS_LINKED(id)); - - BKE_libblock_relink_to_newid_new(bmain, id); - } - - /* Remove linked IDs when a local existing data has been reused instead. */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - BLI_assert(id->newid != NULL); - - id->tag |= LIB_TAG_DOIT; - item->new_id = id->newid; - } - BKE_id_multi_tagged_delete(bmain); - - /* Instantiate newly created (duplicated) IDs as needed. */ - wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d); - - /* Attempt to deal with object proxies. - * - * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not - * producing any useful result in any known use case), neither here nor in - * `BKE_library_make_local` currently. - * Proxies are end of life anyway, so not worth spending time on this. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - - /* Attempt to re-link copied proxy objects. This allows appending of an entire scene - * from another blend file into this one, even when that blend file contains proxified - * armatures that have local references. Since the proxified object needs to be linked - * (not local), this will only work when the "Localize all" checkbox is disabled. - * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ - if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { - Object *ob = (Object *)id; - Object *ob_new = (Object *)id->newid; - bool is_local = false, is_lib = false; - - /* Proxies only work when the proxified object is linked-in from a library. */ - if (!ID_IS_LINKED(ob->proxy)) { - CLOG_WARN(&LOG, - "Proxy object %s will lose its link to %s, because the " - "proxified object is local", - id->newid->name, - ob->proxy->id.name); - continue; - } - - BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); - - /* We can only switch the proxy'ing to a made-local proxy if it is no longer - * referred to from a library. Not checking for local use; if new local proxy - * was not used locally would be a nasty bug! */ - if (is_local || is_lib) { - CLOG_WARN(&LOG, - "Made-local proxy object %s will lose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", - id->newid->name, - ob->proxy->id.name, - is_local, - is_lib); - } - else { - /* we can switch the proxy'ing from the linked-in to the made-local proxy. - * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that - * was already allocated by object_make_local() (which called BKE_object_copy). */ - ob_new->proxy = ob->proxy; - ob_new->proxy_group = ob->proxy_group; - ob_new->proxy_from = ob->proxy_from; - ob_new->proxy->proxy_from = ob_new; - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - } - } - } - - BKE_main_id_newptr_and_tag_clear(bmain); -} - -static void wm_link_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - Main *mainl; - BlendHandle *bh; - Library *lib; - - const int flag = lapp_data->flag; - const int id_tag_extra = 0; - - LinkNode *liblink, *itemlink; - int lib_idx, item_idx; - - BLI_assert(lapp_data->num_items && lapp_data->num_libraries); - - for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; - lib_idx++, liblink = liblink->next) { - char *libname = liblink->link; - BlendFileReadReport bf_reports = {.reports = reports}; - - if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { - bh = BLO_blendhandle_from_memory( - datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports); - } - else { - bh = BLO_blendhandle_from_file(libname, &bf_reports); - } - - if (bh == NULL) { - /* Unlikely since we just browsed it, but possible - * Error reports will have been made by BLO_blendhandle_from_file() */ - continue; - } - - /* here appending/linking starts */ - struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); - /* In case of append, do not handle instantiation in linking process, but during append phase - * (see #wm_append_loose_data_instantiate ). */ - if ((flag & FILE_LINK) == 0) { - liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; - } - - mainl = BLO_library_link_begin(&bh, libname, &liblink_params); - lib = mainl->curlib; - BLI_assert(lib); - UNUSED_VARS_NDEBUG(lib); - - if (mainl->versionfile < 250) { - BKE_reportf(reports, - RPT_WARNING, - "Linking or appending from a very old .blend file format (%d.%d), no animation " - "conversion will " - "be done! You may want to re-save your lib file with current Blender", - mainl->versionfile, - mainl->subversionfile); - } - - /* For each lib file, we try to link all items belonging to that lib, - * and tag those successful to not try to load them again with the other libs. */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *new_id; - - if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { - continue; - } - - new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params); - - if (new_id) { - /* If the link is successful, clear item's libs 'todo' flags. - * This avoids trying to link same item with other libraries to come. */ - BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries); - item->new_id = new_id; - item->source_library = new_id->lib; - } - } - - BLO_library_link_end(mainl, &bh, &liblink_params); - BLO_blendhandle_close(bh); - } -} - /** * Check if an item defined by \a name and \a group can be appended/linked. * @@ -1048,7 +217,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; char *group, *name; int totfiles = 0; @@ -1115,7 +284,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* We define our working data... * Note that here, each item 'uses' one library, and only one. */ - lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C)); + + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); + if (totfiles != 0) { GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); int lib_idx = 0; @@ -1133,7 +309,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (!BLI_ghash_haskey(libraries, libname)) { BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); lib_idx++; - wm_link_append_data_library_add(lapp_data, libname); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); } } } @@ -1145,7 +321,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_join_dirfile(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { continue; @@ -1153,9 +329,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); - item = wm_link_append_data_item_add( - lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, lib_idx); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx); } } RNA_END; @@ -1163,16 +339,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_ghash_free(libraries, MEM_freeN, NULL); } else { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; - wm_link_append_data_library_add(lapp_data, libname); - item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); } - if (lapp_data->num_items == 0) { + if (BKE_blendfile_link_append_context_is_empty(lapp_context)) { /* Early out in case there is nothing to link. */ - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* Clear pre existing tag. */ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return OPERATOR_CANCELLED; @@ -1181,7 +358,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ // BKE_main_lock(bmain); - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_link(lapp_context, op->reports); // BKE_main_unlock(bmain); @@ -1191,10 +368,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* append, rather than linking */ if (do_append) { - wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_append(lapp_context, op->reports); } - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* important we unset, otherwise these object won't * link into other scenes from this blend file */ @@ -1346,23 +523,29 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* Define working data, with just the one item we want to link. */ - WMLinkAppendData *lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); - wm_link_append_data_library_add(lapp_data, filepath); - WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL); + BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add( + lapp_context, id_name, id_code, NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); /* Link datablock. */ - wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_link(lapp_context, NULL); if (do_append) { - wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_append(lapp_context, NULL); } /* Get linked datablock and free working data. */ - ID *id = item->new_id; + ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); @@ -1439,291 +622,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_CANCELLED; } -static void lib_relocate_do_remap(Main *bmain, - ID *old_id, - ID *new_id, - ReportList *reports, - const bool do_reload, - const short remap_flags) -{ - BLI_assert(old_id); - if (do_reload) { - /* Since we asked for placeholders in case of missing IDs, - * we expect to always get a valid one. */ - BLI_assert(new_id); - } - if (new_id) { - CLOG_INFO(&LOG, - 4, - "Before remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); - - if (old_id->flag & LIB_FAKEUSER) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } - - CLOG_INFO(&LOG, - 4, - "After remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - - /* In some cases, new_id might become direct link, remove parent of library in this case. */ - if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { - if (do_reload) { - BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ - } - new_id->lib->parent = NULL; - } - } - - if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { - /* Note that this *should* not happen - but better be safe than sorry in this area, - * at least until we are 100% sure this cannot ever happen. - * Also, we can safely assume names were unique so far, - * so just replacing '.' by '~' should work, - * but this does not totally rules out the possibility of name collision. */ - size_t len = strlen(old_id->name); - size_t dot_pos; - bool has_num = false; - - for (dot_pos = len; dot_pos--;) { - char c = old_id->name[dot_pos]; - if (c == '.') { - break; - } - if (c < '0' || c > '9') { - has_num = false; - break; - } - has_num = true; - } - - if (has_num) { - old_id->name[dot_pos] = '~'; - } - else { - len = MIN2(len, MAX_ID_NAME - 7); - BLI_strncpy(&old_id->name[len], "~000", 7); - } - - id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); - - BKE_reportf( - reports, - RPT_WARNING, - "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " - "old one (%d remaining users) had to be kept and was renamed to '%s'", - new_id->name, - old_id->us, - old_id->name); - } -} - -static void lib_relocate_do(bContext *C, - Library *library, - WMLinkAppendData *lapp_data, - ReportList *reports, - const bool do_reload) -{ - ListBase *lbarray[INDEX_ID_MAX]; - int lba_idx; - - LinkNode *itemlink; - int item_idx; - - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* Remove all IDs to be reloaded from Main. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id = lbarray[lba_idx]->first; - const short idcode = id ? GS(id->name) : 0; - - if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { - /* No need to reload non-linkable datatypes, - * those will get relinked with their 'users ID'. */ - continue; - } - - for (; id; id = id->next) { - if (id->lib == library) { - WMLinkAppendDataItem *item; - - /* We remove it from current Main, and add it to items to link... */ - /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ - BLI_remlink(lbarray[lba_idx], id); - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(id); - if (old_key != NULL) { - BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - - item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); - BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); - - CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); - } - } - } - - if (lapp_data->num_items == 0) { - /* Early out in case there is nothing to do. */ - return; - } - - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - - /* We do not want any instantiation here! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); - - BKE_main_lock(bmain); - - /* We add back old id to bmain. - * We need to do this in a first, separated loop, otherwise some of those may not be handled by - * ID remapping, which means they would still reference old data to be deleted... */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - BLI_assert(old_id); - BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); - - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(old_id); - if (old_key != NULL) { - BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - } - - /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking - * code is wrong, we need to redo it here after adding them back to main. */ - BKE_main_id_refcount_recompute(bmain, false); - - /* Note that in reload case, we also want to replace indirect usages. */ - const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | - ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | - (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - ID *new_id = item->new_id; - - lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); - if (new_id == NULL) { - continue; - } - /* Usual special code for ShapeKeys snowflakes... */ - Key **old_key_p = BKE_key_from_id_p(old_id); - if (old_key_p == NULL) { - continue; - } - Key *old_key = *old_key_p; - Key *new_key = BKE_key_from_id(new_id); - if (old_key != NULL) { - *old_key_p = NULL; - id_us_min(&old_key->id); - lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); - *old_key_p = old_key; - id_us_plus_no_lib(&old_key->id); - } - } - - BKE_main_unlock(bmain); - - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - if (old_id->us == 0) { - BKE_id_free(bmain, old_id); - } - } - - /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable - * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id, *id_next; - for (id = lbarray[lba_idx]->first; id; id = id_next) { - id_next = id->next; - /* XXX That check may be a bit to generic/permissive? */ - if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { - BKE_id_free(bmain, id); - } - } - } - - /* Get rid of no more used libraries... */ - BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id; - for (id = lbarray[lba_idx]->first; id; id = id->next) { - if (id->lib) { - id->lib->id.tag &= ~LIB_TAG_DOIT; - } - } - } - Library *lib, *lib_next; - for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { - lib_next = lib->id.next; - if (lib->id.tag & LIB_TAG_DOIT) { - id_us_clear_real(&lib->id); - if (lib->id.us == 0) { - BKE_id_free(bmain, (ID *)lib); - } - } - } - - /* Update overrides of reloaded linked data-blocks. */ - ID *id; - FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || - (id->tag & LIB_TAG_PRE_EXISTING) == 0) { - continue; - } - if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { - BKE_lib_override_library_update(bmain, id); - } - } - FOREACH_MAIN_ID_END; - - /* Resync overrides if needed. */ - if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { - BKE_lib_override_library_main_resync(bmain, - scene, - view_layer, - &(struct BlendFileReadReport){ - .reports = reports, - }); - /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ - BKE_lib_override_library_main_operations_create(bmain, true); - } - - BKE_main_collection_sync(bmain); - - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object won't - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); -} - void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { if (!BLO_has_bfile_extension(lib->filepath_abs)) { @@ -1740,14 +638,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) return; } - WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | - BLO_LIBLINK_FORCE_INDIRECT); + Main *bmain = CTX_data_main(C); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, + bmain, + BLO_LIBLINK_USE_PLACEHOLDERS | + BLO_LIBLINK_FORCE_INDIRECT, + 0, + CTX_data_scene(C), + CTX_data_view_layer(C), + NULL); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); - wm_link_append_data_library_add(lapp_data, lib->filepath_abs); + BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL); - lib_relocate_do(C, lib, lapp_data, reports, true); + BKE_blendfile_library_relocate(lapp_context, reports, lib, true); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1763,7 +681,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) if (lib) { Main *bmain = CTX_data_main(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; short flag = 0; @@ -1808,13 +726,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL); + if (BLI_path_cmp(lib->filepath_abs, path) == 0) { CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us); do_reload = true; - lapp_data = wm_link_append_data_new(flag); - wm_link_append_data_library_add(lapp_data, path); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } else { int totfiles = 0; @@ -1834,7 +756,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } - lapp_data = wm_link_append_data_new(flag); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); if (totfiles) { RNA_BEGIN (op->ptr, itemptr, "files") { @@ -1847,27 +769,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } RNA_END; } else { CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } } if (do_reload) { - lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + BKE_blendfile_link_append_context_flag_set( + lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true); } - lib_relocate_do(C, lib, lapp_data, op->reports, do_reload); + BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, root, FILE_MAX); + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend + * file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 658424b84a6..35f6ce40dba 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1394,7 +1394,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, wmWindow *win, ListBase *handlers, const char *opname, - int UNUSED(opcontext), + wmOperatorCallContext UNUSED(opcontext), IDProperty *properties, const bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1430,7 +1430,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1543,7 +1543,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1642,7 +1642,7 @@ static bool kmi_filter_is_visible(const wmKeyMap *UNUSED(km), char *WM_key_event_operator_string(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, char *result, @@ -1682,7 +1682,7 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km, */ wmKeyMapItem *WM_key_event_operator(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const short include_mask, const short exclude_mask, diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 1130ad9a558..ffdc99152b1 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1064,7 +1064,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op) } /* invoke callback, uses enum property named "type" */ -int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext) +int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext) { PropertyRNA *prop = op->type->prop; @@ -1216,7 +1216,7 @@ int WM_operator_confirm_message_ex(bContext *C, const char *title, const int icon, const char *message, - const short opcontext) + const wmOperatorCallContext opcontext) { IDProperty *properties = op->ptr->data; diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index fa21dbcb4bb..640fef82085 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -1570,7 +1570,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) /* initialize the font */ BLF_init(); ps.fontid = BLF_load_mono_default(false); - BLF_size(ps.fontid, 11, 72); + BLF_size(ps.fontid, 11.0f, 72); ps.ibufx = ibuf->x; ps.ibufy = ibuf->y; @@ -1845,7 +1845,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv) } IMB_exit(); - BKE_images_exit(); DEG_free_node_types(); totblock = MEM_get_memory_blocks_in_use(); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 40e4d905fcd..9b0f128d071 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -32,6 +32,7 @@ struct ARegion; struct GHOST_TabletData; struct ScrArea; +enum wmOperatorCallContext; #ifdef WITH_XR_OPENXR struct wmXrActionData; @@ -175,6 +176,7 @@ void wm_dropbox_free(void); void wm_drags_exit(wmWindowManager *wm, wmWindow *win); void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop); void wm_drags_check_ops(bContext *C, const wmEvent *event); +wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop); void wm_drags_draw(bContext *C, wmWindow *win); #ifdef __cplusplus diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c index 112312bab7b..f3470edf2f7 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c @@ -432,10 +432,10 @@ static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actionda const XrGrabData *data) { /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both - controllers are pressed) and 2) bimanual interaction occurred on the last update. This second - part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to - two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas - are calculated). */ + * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second + * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to + * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas + * are calculated). */ return (actiondata->bimanual && data->bimanual_prev); } @@ -545,7 +545,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven /* Check if navigation is locked. */ if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) { /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from - two-handed to one-handed interaction) at the end of a bimanual interaction. */ + * two-handed to one-handed interaction) at the end of a bimanual interaction. */ if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) { wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual); } @@ -554,9 +554,9 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven wm_xr_navigation_grab_bimanual_state_update(actiondata, data); /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event - dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal - handling starts when an input is "pressed" (action state exceeds the action threshold) and - ends when the input is "released" (state falls below the threshold). */ + * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal + * handling starts when an input is "pressed" (action state exceeds the action threshold) and + * ends when the input is "released" (state falls below the threshold). */ switch (event->val) { case KM_PRESS: return OPERATOR_RUNNING_MODAL; |