diff options
Diffstat (limited to 'source')
206 files changed, 4383 insertions, 2458 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 78252bdb08b..217a4d5d918 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(); @@ -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_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..d536a0b8486 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) { @@ -617,31 +589,22 @@ void blf_font_draw_buffer(FontBLF *font, * - #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; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1439,6 +1374,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..a9d00151e99 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)); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Cache + * \{ */ - 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; +/** + * Find a glyph cache that matches a size, DPI & styles. + */ +GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int 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; +} - if (err) { - BLI_spin_unlock(font->ft_lib_mutex); - 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; } - /* get the glyph. */ - slot = font->face->glyph; - err = FT_Render_Glyph(slot, render_mode); + /* Render the glyph curves to a bitmap. */ + FT_Error err = FT_Render_Glyph(glyph, render_mode); + if (err != 0) { + return false; + } + + 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..a715d5df692 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -139,14 +139,10 @@ 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..aae666fa182 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -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 { @@ -214,6 +207,9 @@ typedef struct FontBLF { /* font size. */ unsigned int 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..12a83f7634e 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -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_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index 766a3f34a66..3478eebbeb4 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -429,7 +429,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_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 6bdec0d70f3..00934ef2002 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 41 +#define BLENDER_FILE_SUBVERSION 1 /* 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_global.h b/source/blender/blenkernel/BKE_global.h index bacdd4adc76..1e3fe61552a 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -212,7 +212,7 @@ 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. */ 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_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..645b4410623 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -735,7 +735,9 @@ void nodeSetSocketAvailability(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); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d4ec7fd703d..b2418d0539c 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -192,7 +192,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 diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 7403b7f2109..cae72ddf68c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -175,7 +175,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 13f66445c46..03043f3b784 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/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/brush.c b/source/blender/blenkernel/intern/brush.c index 7d217d6907d..dc3c2a8e55e 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) 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/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..6e03f362160 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]; 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/icons.cc b/source/blender/blenkernel/intern/icons.cc index f820b345c59..ffc39028400 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" @@ -383,6 +384,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 311199f8833..c0efc246567 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. */ @@ -5101,11 +5120,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; } @@ -5124,9 +5143,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); } } @@ -5140,7 +5159,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); @@ -5148,7 +5167,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); @@ -5168,6 +5187,7 @@ typedef struct ImagePoolItem { typedef struct ImagePool { ListBase image_buffers; BLI_mempool *memory_pool; + ThreadMutex mutex; } ImagePool; ImagePool *BKE_image_pool_new(void) @@ -5175,21 +5195,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); } @@ -5221,28 +5248,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; @@ -5253,7 +5286,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; } @@ -5642,7 +5675,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); @@ -5657,7 +5690,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; @@ -5686,7 +5719,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); @@ -5700,14 +5733,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); @@ -5717,7 +5750,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; } @@ -5730,7 +5763,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); @@ -5745,7 +5778,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; } @@ -5763,7 +5796,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); @@ -5776,7 +5809,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/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..3a4e39812ab 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); } 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_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index b8fcc10be44..1769be54211 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1279,7 +1279,7 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) /** * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval` - * support this since virtual-modieirs are not modifiers from auser perspective, + * support this since virtual-modifiers are not modifiers from a user perspective, * allowing shape keys to be included with the modifier being applied, see: T91923. */ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, 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/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 0827a15dea0..eb2b125e7e6 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" @@ -248,6 +249,13 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy( *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) @@ -303,12 +311,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 +372,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)); } } @@ -633,6 +649,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) @@ -663,6 +681,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! */ @@ -826,6 +845,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 */ } @@ -1049,8 +1071,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; @@ -1139,15 +1160,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, @@ -3997,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 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). */ -void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) +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(); @@ -4019,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 *********** */ @@ -5477,6 +5533,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 9073fd6adbb..d650003afe2 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. */ @@ -1775,7 +1794,7 @@ static void object_update_from_subsurf_ccg(Object *object) * it is orig as in what was in object_eval->data before evaluating * modifier stack. * - * mesh_cow is a copy-on-written version od object_orig->data. + * mesh_cow is a copy-on-written version of `object_orig->data`. */ Mesh *mesh_cow = (Mesh *)object->runtime.data_orig; copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS); @@ -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]; }; @@ -5400,7 +5409,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. * @@ -5426,7 +5435,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 feb997a4c5d..5b62761bd91 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/scene.c b/source/blender/blenkernel/intern/scene.c index d7fc2005ab2..04106e6f42a 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/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/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_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/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_common.cc b/source/blender/blenloader/intern/versioning_common.cc index c7ff496fa20..61119b80fdd 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -127,9 +127,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_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 809adc493f4..2d5d6479234 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -321,11 +321,16 @@ 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)); } @@ -704,8 +709,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 +741,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 +797,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 8afa631ffc5..f06f6f7d329 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -65,7 +65,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/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/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/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_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/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 32fd1c9ad41..cac6e9965b6 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; + } + else 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/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 c57d121a18f..1a2d3f5837a 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 d2fd8ab88a4..f7c567c89f6 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -18,19 +18,13 @@ * \ingroup edasset */ -#include "BKE_asset.h" -#include "BKE_asset_catalog.hh" #include "BKE_asset_library.hh" #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_report.h" -#include "BLI_string_ref.hh" -#include "BLI_vector.hh" - #include "ED_asset.h" -#include "ED_asset_catalog.hh" /* XXX needs access to the file list, should all be done via the asset system in future. */ #include "ED_fileselect.h" @@ -38,7 +32,6 @@ #include "RNA_define.h" #include "WM_api.h" -#include "WM_types.h" using namespace blender; 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/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..bdb4e485373 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); @@ -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_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_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_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 3e9f22f25d3..8d72ea72532 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); @@ -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..f3c3aa10632 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, @@ -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/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 aa86f07692d..38f607dddcb 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -609,12 +609,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 725c9921d13..207318de981 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" { @@ -691,7 +692,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); @@ -1002,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, @@ -1012,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, @@ -1185,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, @@ -1195,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, @@ -1381,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, @@ -1392,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, @@ -1723,7 +1724,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); @@ -1963,7 +1964,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); @@ -2391,7 +2392,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, @@ -2399,7 +2400,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, @@ -2407,7 +2408,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); @@ -2487,14 +2488,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/interface/interface.c b/source/blender/editors/interface/interface.c index dc9eaed5731..82ea218baba 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1638,7 +1638,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 +1678,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 +1881,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}); } @@ -4742,7 +4742,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, @@ -5280,7 +5280,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, @@ -5295,7 +5295,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, @@ -5663,7 +5663,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, @@ -5678,7 +5678,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, @@ -6066,7 +6066,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, @@ -6083,7 +6083,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, 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_handlers.c b/source/blender/editors/interface/interface_handlers.c index 51ebe5399b3..35e1526d079 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); } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index f849ec55e4f..d0a7716b4dd 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1484,7 +1484,7 @@ PreviewImage *UI_icon_to_preview(int icon_id) /** * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for - * #ICON_TYPE_IMBUF because it's a backported fix for performance issues, see T92922. Only + * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable. * * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index f766bb1465f..c7c6a88de01 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; @@ -882,7 +882,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 +960,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_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_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_style.c b/source/blender/editors/interface/interface_style.c index 92a9f14c77d..4c640851999 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) { @@ -490,9 +490,13 @@ void uiStyleInit(void) } 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); diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index d3ce7ebc3db..7b2fb8f784e 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.c index 5877b4fe6d7..26250e105eb 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -115,7 +115,7 @@ struct MenuSearch_Item { struct { wmOperatorType *type; PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; bContextStore *context; } op; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1d349aa0596..b30a86c5fcf 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/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/object/object_add.c b/source/blender/editors/object/object_add.c index 90caeecd91f..8b5894923ad 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2145,7 +2145,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; @@ -2378,7 +2378,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); @@ -3374,8 +3374,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/screen/area.c b/source/blender/editors/screen/area.c index 80c14371c16..8523496bdbd 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -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. */ 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/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/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_file/filelist.c b/source/blender/editors/space_file/filelist.c index a1b1c8cc363..a73fa2b9740 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1911,6 +1911,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, @@ -2010,7 +2011,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)); 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_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..62f40ae625d 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,7 +168,7 @@ 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; } @@ -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/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index b6c24a55a78..5fdf816339b 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -1107,21 +1107,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"; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index f5aabecd309..fc20739b5e2 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -997,7 +997,7 @@ void ED_spacetype_sequencer(void) art->draw_overlay = sequencer_main_region_draw_overlay; art->listener = sequencer_main_region_listener; art->message_subscribe = sequencer_main_region_message_subscribe; - /* NOTE: inclusion of #ED_KEYMAP_GIZMO is currenlty for scripts and isn't used by default. */ + /* NOTE: inclusion of #ED_KEYMAP_GIZMO is currently for scripts and isn't used by default. */ art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 91fe1bc01b7..192b80881ee 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -67,4 +67,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..50b67c55bd6 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -319,6 +319,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; } 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..cf048d1bbd8 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" @@ -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; } @@ -487,6 +496,91 @@ 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) @@ -682,6 +776,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..25a9d0f0213 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -20,6 +20,7 @@ #include "DNA_windowmanager_types.h" #include "BKE_context.h" +#include "BKE_volume.h" #include "BLF_api.h" @@ -48,7 +49,7 @@ static int is_component_row_selected(struct uiBut *but, const void *arg) const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain; bool is_selected = is_component_selected && is_domain_selected; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { + if (ELEM(component, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES)) { is_selected = is_component_selected; } @@ -141,6 +142,14 @@ static int element_count_from_instances(const GeometrySet &geometry_set) return 0; } +static int element_count_from_volume(const GeometrySet &geometry_set) +{ + if (const Volume *volume = geometry_set.get_volume_for_read()) { + return BKE_volume_num_grids(volume); + } + return 0; +} + static int element_count_from_component_domain(const GeometrySet &geometry_set, GeometryComponentType component, AttributeDomain domain) @@ -191,6 +200,10 @@ void DatasetRegionDrawer::draw_dataset_row(const int indentation, BLI_str_format_attribute_domain_size( element_count, element_count_from_instances(draw_context.current_geometry_set)); } + else if (component == GEO_COMPONENT_TYPE_VOLUME) { + BLI_str_format_attribute_domain_size( + element_count, element_count_from_volume(draw_context.current_geometry_set)); + } else { BLI_str_format_attribute_domain_size( element_count, @@ -206,7 +219,7 @@ void DatasetRegionDrawer::draw_dataset_row(const int indentation, uiBut *bt = uiDefIconTextButO(&block, UI_BTYPE_DATASETROW, "SPREADSHEET_OT_change_spreadsheet_data_source", - 0, + WM_OP_INVOKE_DEFAULT, icon, label, rect.xmin, @@ -237,7 +250,7 @@ void DatasetRegionDrawer::draw_dataset_row(const int indentation, void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info) { - if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) { + if (ELEM(component_info.type, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES)) { draw_dataset_row( 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc index abbad8c7088..f15af2e4d32 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc @@ -75,6 +75,12 @@ constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = { }, }, { + GEO_COMPONENT_TYPE_VOLUME, + N_("Volume Grids"), + ICON_VOLUME_DATA, + {}, + }, + { GEO_COMPONENT_TYPE_INSTANCES, N_("Instances"), ICON_EMPTY_AXIS, 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_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_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 6acf51aec6e..3a9c9e27ef0 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_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_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/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/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/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/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 4f316150e10..1bc0a4e628d 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); + BLI_mutex_lock(&limitor_lock); + if (item->c_handle) { + MEM_CacheLimiter_unmanage(item->c_handle); + } + BLI_mutex_unlock(&limitor_lock); + if (item->ibuf) { IMB_freeImBuf(item->ibuf); } 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/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_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_node_types.h b/source/blender/makesdna/DNA_node_types.h index d5d2520ddf6..cfe34d83586 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; @@ -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_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5ebc81fff4f..671cc182d7e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -2006,6 +2006,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_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 4f91d6b2fbb..f80fcb9ae78 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -557,7 +557,7 @@ typedef struct bUserMenuItem_Op { bUserMenuItem item; char op_idname[64]; struct IDProperty *prop; - char opcontext; + char opcontext; /* #wmOperatorCallContext */ char _pad0[7]; } bUserMenuItem_Op; 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/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 01889a1b0a9..53b3f07dbbc 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -12753,6 +12753,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_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_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 2514a604087..92f7b7d7682 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); @@ -1131,36 +1139,36 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) prop = RNA_def_property(srna, "points", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 6, 24); 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_theme_text_style_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) 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/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index f4ca9f51b1b..0b4c34d6155 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -39,6 +39,7 @@ set(INC ../makesdna ../makesrna ../render + ../windowmanager ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/sky/include 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/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 167765fa131..ac346eb705b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -67,13 +67,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/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index f068e621596..503711fedfe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -38,7 +38,7 @@ 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")); } 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..ee7a78ccf71 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc @@ -24,7 +24,16 @@ namespace blender::nodes { static void geo_node_curve_parameter_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,52 +86,47 @@ 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, @@ -136,13 +135,50 @@ static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, ResourceScope &scope) { 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 &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(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 &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(values)); + } + return nullptr; +} + +static const GVArray *construct_curve_length_gvarray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain, + ResourceScope &scope) +{ + if (domain == ATTR_DOMAIN_POINT) { + Array<float> lengths = curve_length_point_domain(curve); + return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); + } + + if (domain == ATTR_DOMAIN_CURVE) { + if (curve.splines().size() == 1) { + Array<float> lengths(1, 0.0f); + return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); + } + + Array<float> lengths = curve_length_spline_domain(curve, mask); + return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(lengths)); } return nullptr; @@ -188,10 +224,51 @@ class CurveParameterFieldInput final : public fn::FieldInput { } }; +class CurveLengthFieldInput final : public fn::FieldInput { + public: + CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node") + { + category_ = Category::Generated; + } + + const 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)) { + + 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_gvarray(*curve, mask, domain, scope); + } + } + } + return nullptr; + } + + 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 geo_node_curve_parameter_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 @@ -199,7 +276,6 @@ static void geo_node_curve_parameter_exec(GeoNodeExecParams params) void register_node_type_geo_curve_parameter() { 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; 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..673a5095044 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 @@ -29,15 +29,27 @@ static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuild .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")); } 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..ffede480c75 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 @@ -25,17 +25,34 @@ namespace blender::nodes { static void geo_node_curve_primitive_circle_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")); } 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..37a5989d3f1 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 @@ -25,10 +25,21 @@ namespace blender::nodes { static void geo_node_curve_primitive_line_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")); } 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..27bf4a310df 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 @@ -25,14 +25,20 @@ static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBui .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")); } 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..e00a502bf32 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 @@ -23,31 +23,57 @@ namespace blender::nodes { static void geo_node_curve_primitive_quadrilateral_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")); } 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..1384165e520 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 @@ -26,12 +26,26 @@ static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b) .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")); } 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..7f682b198b3 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 @@ -22,16 +22,25 @@ namespace blender::nodes { static void geo_node_curve_primitive_star_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")); } 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..4dad3d22283 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -35,6 +35,7 @@ namespace blender::nodes { static void geo_node_curve_resample_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) @@ -63,7 +64,7 @@ static void geo_node_curve_resample_update(bNodeTree *UNUSED(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); @@ -74,6 +75,7 @@ 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) @@ -183,42 +185,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; } @@ -244,6 +268,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) { 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..ca6254be182 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -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) { 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..f1f95be107a 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 @@ -29,8 +29,15 @@ namespace blender::nodes { static void geo_node_mesh_primitive_circle_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")); } 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..01378431ca6 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,20 +25,45 @@ #include "node_geometry_util.hh" +#include <cmath> + 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::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); - b.add_input<decl::Float>(N_("Depth")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); + .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 geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node) @@ -94,6 +119,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 +134,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 +168,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 +180,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 +217,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 +311,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 +338,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 +559,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 +756,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 +775,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,6 +787,7 @@ 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); @@ -708,38 +801,76 @@ static void geo_node_mesh_primitive_cone_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 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)); } 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..b5903f7b71e 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 @@ -29,10 +29,23 @@ 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); + .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")); } 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..51ecff72e68 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 @@ -33,17 +33,17 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) .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,8 +53,11 @@ 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_("Bottom")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); } static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout, @@ -97,33 +100,71 @@ 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)); } 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..73c679e18f8 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 @@ -29,10 +29,26 @@ 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_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")); } 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..e4bf5e31dbf 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 @@ -28,8 +28,16 @@ namespace blender::nodes { static void geo_node_mesh_primitive_ico_sphere_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, 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..df4efb2427c 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 @@ -29,12 +29,25 @@ namespace blender::nodes { static void geo_node_mesh_primitive_line_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")); } 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..3197a94c27b 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 @@ -29,9 +29,21 @@ namespace blender::nodes { static void geo_node_mesh_primitive_uv_shpere_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")); } 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..f969baa9584 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -27,9 +27,8 @@ static void geo_node_object_info_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")); 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..18d674a38a4 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 @@ -222,16 +222,12 @@ 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); } 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..27bc206187d 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; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 11356178d87..dce54d58dce 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -269,10 +269,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. 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/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 112d76a3e65..8d25ece3753 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 */ @@ -472,26 +472,26 @@ bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op); bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op); 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/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 85378ffd7c7..29ba346c2f6 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 798f60fba3d..f51c8c48c48 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) { @@ -1613,7 +1616,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct IDProperty *properties) { PointerRNA props_ptr; @@ -1644,7 +1647,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) @@ -1768,8 +1771,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; @@ -3063,8 +3069,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..d373ecdac77 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -52,6 +52,8 @@ #include "BLO_readfile.h" +#include "BLT_translation.h" + #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_global.h" @@ -354,7 +356,8 @@ static void wm_append_loose_data_instantiate_ensure_active_collection( *r_active_collection = lc->collection; } else { - *r_active_collection = BKE_collection_add(bmain, scene->master_collection, NULL); + *r_active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Appended Data")); } } } @@ -438,11 +441,13 @@ static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data, 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) { + 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) { @@ -812,7 +817,7 @@ static void wm_append_do(WMLinkAppendData *lapp_data, BLI_assert(!ID_IS_LINKED(id)); - BKE_libblock_relink_to_newid_new(bmain, id); + BKE_libblock_relink_to_newid(bmain, id, 0); } /* Remove linked IDs when a local existing data has been reused instead. */ 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..a41fa94e8c2 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -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/creator/creator.c b/source/creator/creator.c index 7c99f954bfc..4171d60b5b6 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -414,7 +414,6 @@ int main(int argc, BKE_idtype_init(); BKE_cachefiles_init(); - BKE_images_init(); BKE_modifier_init(); BKE_gpencil_modifier_init(); BKE_shaderfx_init(); |