diff options
Diffstat (limited to 'source/blender')
350 files changed, 11262 insertions, 4718 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 83ca9158efc..75824ae056f 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -18,10 +18,10 @@ extern "C" { #define BLF_DATAFILES_FONTS_DIR "fonts" /* File name of the default variable-width font. */ -#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf" +#define BLF_DEFAULT_PROPORTIONAL_FONT "DejaVuSans.woff2" /* File name of the default fixed-pitch font. */ -#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf" +#define BLF_DEFAULT_MONOSPACED_FONT "DejaVuSansMono.woff2" /* enable this only if needed (unused circa 2016) */ #define BLF_BLUR_ENABLE 0 @@ -351,6 +351,8 @@ enum { BLF_DEFAULT = 1 << 14, /** Must only be used as last font in the stack. */ BLF_LAST_RESORT = 1 << 15, + /** Failure to load this font. Don't try again. */ + BLF_BAD_FONT = 1 << 16, }; #define BLF_DRAW_STR_DUMMY_MAX 1024 diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index a1fcc17ca3f..36475321d4c 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -122,7 +122,7 @@ bool BLF_has_glyph(int fontid, unsigned int unicode) { FontBLF *font = blf_get(fontid); if (font) { - return FT_Get_Char_Index(font->face, unicode) != FT_Err_Ok; + return blf_get_char_index(font, unicode) != FT_Err_Ok; } return false; } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 038e73cc928..5f904d86b03 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -18,8 +18,9 @@ #include FT_FREETYPE_H #include FT_GLYPH_H -#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ +#include FT_TRUETYPE_IDS_H /* Codepoint coverage constants. */ +#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include "MEM_guardedalloc.h" @@ -28,6 +29,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_math_color_blend.h" +#include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_string_utf8.h" @@ -52,7 +54,8 @@ BatchBLF g_batch; /* freetype2 handle ONLY for this file! */ -static FT_Library ft_lib; +static FT_Library ft_lib = NULL; + static SpinLock ft_lib_mutex; static SpinLock blf_glyph_cache_mutex; @@ -63,19 +66,27 @@ static ft_pix blf_font_height_max_ft_pix(struct FontBLF *font); static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font); /* -------------------------------------------------------------------- */ + +/* Return glyph id from charcode. */ +uint blf_get_char_index(struct FontBLF *font, uint charcode) +{ + return FT_Get_Char_Index(font->face, charcode); +} + +/* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ -/* Convert a FreeType 26.6 value representing an unscaled design size to factional pixels. */ +/* Convert a FreeType 26.6 value representing an unscaled design size to fractional pixels. */ static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) { /* Scale value by font size using integer-optimized multiplication. */ - FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale); + FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale); /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down */ /* kerning distances at small ppem values so that they don't become too big. */ - if (font->face->size->metrics.x_ppem < 25) { - scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25); + if (font->ft_size->metrics.x_ppem < 25) { + scaled = FT_MulDiv(scaled, font->ft_size->metrics.x_ppem, 25); } return (ft_pix)scaled; @@ -294,7 +305,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph /* Small adjust if there is hinting. */ adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0); - if (FT_HAS_KERNING(font->face) && g_prev) { + if (FT_HAS_KERNING(font) && g_prev) { FT_Vector delta = {KERNING_ENTRY_UNSET}; /* Get unscaled kerning value from our cache if ASCII. */ @@ -303,7 +314,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph } /* If not ASCII or not found in cache, ask FreeType for kerning. */ - if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) { + if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) { /* Note that this function sets delta values to zero on any error. */ FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta); } @@ -836,7 +847,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, size_t i = 0, i_curr; rcti gbox_px; - if (str_len == 0) { + if (str_len == 0 || str[0] == 0) { /* early output. */ return; } @@ -923,8 +934,7 @@ static void blf_font_wrap_apply(FontBLF *font, int lines = 0; ft_pix pen_x_next = 0; - /* Space between lines needs to be aligned to the pixel grid (T97310). */ - ft_pix line_height = FT_PIX_FLOOR(blf_font_height_max_ft_pix(font)); + ft_pix line_height = blf_font_height_max_ft_pix(font); GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); @@ -1088,7 +1098,7 @@ int blf_font_count_missing_chars(FontBLF *font, } else { c = BLI_str_utf8_as_unicode_step(str, str_len, &i); - if (FT_Get_Char_Index((font)->face, c) == 0) { + if (blf_get_char_index(font, c) == 0) { missing++; } } @@ -1105,18 +1115,8 @@ int blf_font_count_missing_chars(FontBLF *font, static ft_pix blf_font_height_max_ft_pix(FontBLF *font) { - ft_pix height_max; - FT_Face face = font->face; - if (FT_IS_SCALABLE(face)) { - height_max = ft_pix_from_int((int)(face->ascender - face->descender) * - (int)face->size->metrics.y_ppem) / - (ft_pix)face->units_per_EM; - } - else { - height_max = (ft_pix)face->size->metrics.height; - } - /* can happen with size 1 fonts */ - return MAX2(height_max, ft_pix_from_int(1)); + /* Metrics.height is rounded to pixel. Force minimum of one pixel. */ + return MAX2((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1)); } int blf_font_height_max(FontBLF *font) @@ -1126,18 +1126,8 @@ int blf_font_height_max(FontBLF *font) static ft_pix blf_font_width_max_ft_pix(FontBLF *font) { - ft_pix width_max; - const FT_Face face = font->face; - if (FT_IS_SCALABLE(face)) { - width_max = ft_pix_from_int((int)(face->bbox.xMax - face->bbox.xMin) * - (int)face->size->metrics.x_ppem) / - (ft_pix)face->units_per_EM; - } - else { - width_max = (ft_pix)face->size->metrics.max_advance; - } - /* can happen with size 1 fonts */ - return MAX2(width_max, ft_pix_from_int(1)); + /* Metrics.max_advance is rounded to pixel. Force minimum of one pixel. */ + return MAX2((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1)); } int blf_font_width_max(FontBLF *font) @@ -1147,17 +1137,17 @@ int blf_font_width_max(FontBLF *font) int blf_font_descender(FontBLF *font) { - return ft_pix_to_int((ft_pix)font->face->size->metrics.descender); + return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender); } int blf_font_ascender(FontBLF *font) { - return ft_pix_to_int((ft_pix)font->face->size->metrics.ascender); + return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender); } char *blf_display_name(FontBLF *font) { - if (!font->face->family_name) { + if (!blf_ensure_face(font) || !font->face->family_name) { return NULL; } return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name); @@ -1174,13 +1164,16 @@ int blf_font_init(void) memset(&g_batch, 0, sizeof(g_batch)); BLI_spin_init(&ft_lib_mutex); BLI_spin_init(&blf_glyph_cache_mutex); - return FT_Init_FreeType(&ft_lib); + int err = FT_Init_FreeType(&ft_lib); + return err; } void blf_font_exit(void) { - FT_Done_FreeType(ft_lib); BLI_spin_end(&ft_lib_mutex); + if (ft_lib) { + FT_Done_FreeType(ft_lib); + } BLI_spin_end(&blf_glyph_cache_mutex); blf_batch_draw_exit(); } @@ -1244,14 +1237,28 @@ static void blf_font_fill(FontBLF *font) font->glyph_cache_mutex = &blf_glyph_cache_mutex; } -FontBLF *blf_font_new(const char *name, const char *filepath) +/** + * Create an FT_Face for this font if not already existing. + */ +bool blf_ensure_face(FontBLF *font) { - FontBLF *font; + if (font->face) { + return true; + } + + if (font->flags & BLF_BAD_FONT) { + return false; + } + FT_Error err; - char *mfile; - font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); - err = FT_New_Face(ft_lib, filepath, 0, &font->face); + if (font->filepath) { + err = FT_New_Face(ft_lib, font->filepath, 0, &font->face); + } + if (font->mem) { + err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + } + if (err) { if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { printf("Format of this font file is not supported\n"); @@ -1259,8 +1266,8 @@ FontBLF *blf_font_new(const char *name, const char *filepath) else { printf("Error encountered while opening font file\n"); } - MEM_freeN(font); - return NULL; + font->flags |= BLF_BAD_FONT; + return false; } err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE); @@ -1272,28 +1279,31 @@ FontBLF *blf_font_new(const char *name, const char *filepath) } if (err) { printf("Can't set a character map!\n"); - FT_Done_Face(font->face); - MEM_freeN(font); - return NULL; + font->flags |= BLF_BAD_FONT; + return false; } - mfile = blf_dir_metrics_search(filepath); - if (mfile) { - err = FT_Attach_File(font->face, mfile); - if (err) { - fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filepath, (int)err); + if (font->filepath) { + char *mfile = blf_dir_metrics_search(font->filepath); + if (mfile) { + err = FT_Attach_File(font->face, mfile); + if (err) { + fprintf(stderr, + "FT_Attach_File failed to load '%s' with error %d\n", + font->filepath, + (int)err); + } + MEM_freeN(mfile); } - MEM_freeN(mfile); } - if (FT_HAS_MULTIPLE_MASTERS(font->face)) { + font->ft_size = font->face->size; + font->face_flags = font->face->face_flags; + + if (FT_HAS_MULTIPLE_MASTERS(font)) { FT_Get_MM_Var(font->face, &(font->variations)); } - font->name = BLI_strdup(name); - font->filepath = BLI_strdup(filepath); - blf_font_fill(font); - /* Save TrueType table with bits to quickly test most unicode block coverage. */ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2); if (os2_table) { @@ -1303,17 +1313,11 @@ FontBLF *blf_font_new(const char *name, const char *filepath) font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4; } - /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ - if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU && - font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) { - font->flags |= BLF_LAST_RESORT; - } - - if (FT_IS_FIXED_WIDTH(font->face)) { + if (FT_IS_FIXED_WIDTH(font)) { font->flags |= BLF_MONOSPACED; } - if (FT_HAS_KERNING(font->face)) { + if (FT_HAS_KERNING(font) && !font->kerning_cache) { /* Create kerning cache table and fill with value indicating "unset". */ font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__); for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { @@ -1323,49 +1327,116 @@ FontBLF *blf_font_new(const char *name, const char *filepath) } } - return font; + return true; } -void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size) +typedef struct eFaceDetails { + char name[50]; + unsigned int coverage1; + unsigned int coverage2; + unsigned int coverage3; + unsigned int coverage4; +} eFaceDetails; + +/* Details about the fallback fonts we ship, so that we can load only when needed. */ +static const eFaceDetails static_face_details[] = { + {"lastresort.woff2", UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}, + {"Noto Sans CJK Regular.woff2", 0x30000083L, 0x2BDF3C10L, 0x16L, 0}, + {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L}, + {"NotoSansArabic-VariableFont_wdth,wght.woff2", TT_UCR_ARABIC, 0, 0, 0}, + {"NotoSansArmenian-VariableFont_wdth,wght.woff2", + TT_UCR_ARMENIAN, + TT_UCR_ALPHABETIC_PRESENTATION_FORMS, + 0, + 0}, + {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0}, + {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0}, + {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0}, + {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0}, + {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0}, + {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0}, + {"NotoSansHebrew-VariableFont_wdth,wght.woff2", TT_UCR_HEBREW, 0, 0, 0}, + {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0}, + {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0}, + {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0}, + {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0}, + {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0}, + {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0}, + {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L}, + {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0}, + {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0}, + {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0}, +}; + +/* Create a new font from filename OR from passed memory pointer. */ +static FontBLF *blf_font_new_ex(const char *name, + const char *filepath, + const unsigned char *mem, + const size_t mem_size) { - FT_Open_Args open; - - open.flags = FT_OPEN_MEMORY; - open.memory_base = (const FT_Byte *)mem; - open.memory_size = mem_size; - FT_Attach_Stream(font->face, &open); -} + FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); -FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size) -{ - FontBLF *font; - FT_Error err; + font->name = BLI_strdup(name); + font->filepath = filepath ? BLI_strdup(filepath) : NULL; + if (mem) { + font->mem = (void *)mem; + font->mem_size = mem_size; + } + blf_font_fill(font); - font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem"); - err = FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face); - if (err) { - MEM_freeN(font); - return NULL; + /* If we have static details about this font we don't need to load the Face. */ + const eFaceDetails *static_details = NULL; + char filename[256]; + for (int i = 0; i < (int)ARRAY_SIZE(static_face_details); i++) { + BLI_split_file_part(font->filepath, filename, sizeof(filename)); + if (STREQ(static_face_details[i].name, filename)) { + static_details = &static_face_details[i]; + font->UnicodeRanges[0] = static_details->coverage1; + font->UnicodeRanges[1] = static_details->coverage2; + font->UnicodeRanges[2] = static_details->coverage3; + font->UnicodeRanges[3] = static_details->coverage4; + break; + } } - err = FT_Select_Charmap(font->face, ft_encoding_unicode); - if (err) { - printf("Can't set the unicode character map!\n"); - FT_Done_Face(font->face); - MEM_freeN(font); - return NULL; + if (!static_details) { + if (!blf_ensure_face(font)) { + blf_font_free(font); + return NULL; + } } - if (FT_HAS_MULTIPLE_MASTERS(font->face)) { - FT_Get_MM_Var(font->face, &(font->variations)); + /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ + if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU && + font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) { + font->flags |= BLF_LAST_RESORT; } - font->name = BLI_strdup(name); - font->filepath = NULL; - blf_font_fill(font); return font; } +FontBLF *blf_font_new(const char *name, const char *filename) +{ + return blf_font_new_ex(name, filename, NULL, 0); +} + +FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, const size_t mem_size) +{ + return blf_font_new_ex(name, NULL, mem, mem_size); +} + +void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const size_t mem_size) +{ + FT_Open_Args open; + + open.flags = FT_OPEN_MEMORY; + open.memory_base = (const FT_Byte *)mem; + open.memory_size = (FT_Long)mem_size; + if (blf_ensure_face(font)) { + FT_Attach_Stream(font->face, &open); + } +} + void blf_font_free(FontBLF *font) { blf_glyph_cache_clear(font); @@ -1378,7 +1449,10 @@ void blf_font_free(FontBLF *font) FT_Done_MM_Var(ft_lib, font->variations); } - FT_Done_Face(font->face); + if (font->face) { + FT_Done_Face(font->face); + font->face = NULL; + } if (font->filepath) { MEM_freeN(font->filepath); } @@ -1396,8 +1470,12 @@ void blf_font_free(FontBLF *font) bool blf_font_size(FontBLF *font, float size, unsigned int dpi) { + if (!blf_ensure_face(font)) { + return false; + } + /* FreeType uses fixed-point integers in 64ths. */ - FT_F26Dot6 ft_size = lroundf(size * 64.0f); + FT_UInt ft_size = round_fl_to_uint(size * 64.0f); /* Adjust our new size to be on even 64ths. */ size = (float)ft_size / 64.0f; diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index 1bde25b5776..63957fad003 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -66,8 +66,6 @@ void BLF_load_font_stack() } else { BLF_enable(font_id, BLF_DEFAULT); - /* TODO: FontBLF will later load FT_Face on demand. When this is in - * place we can drop this face now since we have all needed data. */ } } } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 215f79e6795..9cdca81af28 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -94,16 +94,16 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->bucket, 0, sizeof(gc->bucket)); /* Determine ideal fixed-width size for monospaced output. */ - FT_UInt gindex = FT_Get_Char_Index(font->face, U'0'); - if (gindex) { + FT_UInt gindex = blf_get_char_index(font, U'0'); + if (gindex && font->face) { FT_Fixed advance = 0; FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); /* Use CSS 'ch unit' width, advance of zero character. */ gc->fixed_width = (int)(advance >> 16); } else { - /* Font does not contain "0" so use CSS fallback of 1/2 of em. */ - gc->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6); + /* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */ + gc->fixed_width = (int)((font->ft_size->metrics.height / 2) >> 6); } if (gc->fixed_width < 1) { gc->fixed_width = 1; @@ -565,7 +565,7 @@ static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit) */ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode) { - FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode); + FT_UInt glyph_index = blf_get_char_index(*font, charcode); if (glyph_index) { return glyph_index; } @@ -584,7 +584,7 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode continue; } if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) { - glyph_index = FT_Get_Char_Index(f->face, charcode); + glyph_index = blf_get_char_index(f, charcode); if (glyph_index) { *font = f; return glyph_index; @@ -592,9 +592,13 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode } } +#ifdef DEBUG + printf("Unicode character U+%04X not found in loaded fonts. \n", charcode); +#endif + /* Not found in the stack, return from Last Resort if there is one. */ if (last_resort) { - glyph_index = FT_Get_Char_Index(last_resort->face, charcode); + glyph_index = blf_get_char_index(last_resort, charcode); if (glyph_index) { *font = last_resort; return glyph_index; @@ -892,13 +896,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, int fixed_width) { 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; + blf_font_size(glyph_font, settings_font->size, settings_font->dpi); } /* We need to keep track if changes are still needed. */ @@ -955,7 +953,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, /* Fallback glyph transforms, but only if required and not yet done. */ if (weight != 0.0f && !weight_done) { - blf_glyph_transform_weight(glyph, weight, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); + blf_glyph_transform_weight(glyph, weight, FT_IS_FIXED_WIDTH(glyph_font)); } if (slant != 0.0f && !slant_done) { blf_glyph_transform_slant(glyph, slant); @@ -984,11 +982,9 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) 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); + if (!blf_ensure_face(font_with_glyph)) { + return NULL; + } FT_GlyphSlot glyph = blf_glyph_render( font, font_with_glyph, glyph_index, charcode, gc->fixed_width); @@ -998,7 +994,6 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index); } - BLI_spin_unlock(font_with_glyph->ft_lib_mutex); return g; } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 84037ff4bd0..221e656f096 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -14,7 +14,7 @@ struct ResultBLF; struct rctf; struct rcti; -/* Max number of fonts in memory. Take care that every font has a glyph cache per size/dpi, +/* Max number of FontBLFs in memory. Take care that every font has a glyph cache per size/dpi, * so we don't need load the same font with different size, just load one and call BLF_size. */ #define BLF_MAX_FONT 32 @@ -39,12 +39,16 @@ void blf_font_exit(void); bool blf_font_id_is_valid(int fontid); +uint blf_get_char_index(struct FontBLF *font, uint charcode); + +bool blf_ensure_face(struct FontBLF *font); + void blf_draw_buffer__start(struct FontBLF *font); void blf_draw_buffer__end(void); struct FontBLF *blf_font_new(const char *name, const char *filepath); -struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); -void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); +struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, size_t mem_size); +void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, size_t mem_size); /** * Change font's output size. Returns true if successful in changing the size. diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 5b55f4af0b8..3064630de1b 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -240,9 +240,13 @@ typedef struct FontBLF { /* # of times this font was loaded */ unsigned int reference_count; - /** File-path or NULL. */ + /* Full path to font file or NULL if from memory. */ char *filepath; + /* Pointer to in-memory font, or NULL if from file. */ + void *mem; + size_t mem_size; + /* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges * considered "functional". Cached here because face might not always exist. * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */ @@ -325,6 +329,12 @@ typedef struct FontBLF { /* freetype2 face. */ FT_Face face; + /* Point to face->size or to cache's size. */ + FT_Size ft_size; + + /* Copy of the font->face->face_flags, in case we don't have a face loaded. */ + FT_Long face_flags; + /* data for buffer usage (drawing into a texture buffer) */ FontBufInfoBLF buf_info; diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 01c2ef988f2..770937688d7 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -188,10 +188,28 @@ template<typename T> class SimpleMixer { * \param default_value: Output value for an element that has not been affected by a #mix_in. */ SimpleMixer(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixer(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixer(MutableSpan<T> buffer, const IndexMask mask, T default_value = {}) : buffer_(buffer), default_value_(default_value), total_weights_(buffer.size(), 0.0f) { BLI_STATIC_ASSERT(std::is_trivial_v<T>, ""); - memset(buffer_.data(), 0, sizeof(T) * buffer_.size()); + mask.foreach_index([&](const int64_t i) { buffer_[i] = default_value_; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + BLI_assert(weight >= 0.0f); + buffer_[index] = value * weight; + total_weights_[index] = weight; } /** @@ -209,7 +227,12 @@ template<typename T> class SimpleMixer { */ void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(IndexMask(buffer_.size())); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; if (weight > 0.0f) { buffer_[i] *= 1.0f / weight; @@ -217,7 +240,7 @@ template<typename T> class SimpleMixer { else { buffer_[i] = default_value_; } - } + }); } }; @@ -237,9 +260,25 @@ class BooleanPropagationMixer { /** * \param buffer: Span where the interpolated values should be stored. */ - BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer) + BooleanPropagationMixer(MutableSpan<bool> buffer) + : BooleanPropagationMixer(buffer, buffer.index_range()) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + BooleanPropagationMixer(MutableSpan<bool> buffer, const IndexMask mask) : buffer_(buffer) + { + mask.foreach_index([&](const int64_t i) { buffer_[i] = false; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f) { - buffer_.fill(false); + buffer_[index] = value; } /** @@ -256,6 +295,10 @@ class BooleanPropagationMixer { void finalize() { } + + void finalize(const IndexMask /*mask*/) + { + } }; /** @@ -277,8 +320,27 @@ class SimpleMixerWithAccumulationType { public: SimpleMixerWithAccumulationType(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixerWithAccumulationType(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixerWithAccumulationType(MutableSpan<T> buffer, + const IndexMask mask, + T default_value = {}) : buffer_(buffer), default_value_(default_value), accumulation_buffer_(buffer.size()) { + mask.foreach_index([&](const int64_t index) { buffer_[index] = default_value_; }); + } + + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + const AccumulationT converted_value = static_cast<AccumulationT>(value); + Item &item = accumulation_buffer_[index]; + item.value = converted_value * weight; + item.weight = weight; } void mix_in(const int64_t index, const T &value, const float weight = 1.0f) @@ -291,7 +353,12 @@ class SimpleMixerWithAccumulationType { void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const Item &item = accumulation_buffer_[i]; if (item.weight > 0.0f) { const float weight_inv = 1.0f / item.weight; @@ -301,7 +368,7 @@ class SimpleMixerWithAccumulationType { else { buffer_[i] = default_value_; } - } + }); } }; @@ -314,8 +381,16 @@ class ColorGeometry4fMixer { public: ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, + IndexMask mask, + ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + void set(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; class ColorGeometry4bMixer { @@ -328,8 +403,16 @@ class ColorGeometry4bMixer { public: ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, + IndexMask mask, + ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + void set(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; template<typename T> struct DefaultMixerStruct { @@ -381,12 +464,12 @@ template<> struct DefaultMixerStruct<int8_t> { using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>; }; -template<typename T> struct DefaultPropatationMixerStruct { +template<typename T> struct DefaultPropagationMixerStruct { /* Use void by default. This can be checked for in `if constexpr` statements. */ using type = typename DefaultMixerStruct<T>::type; }; -template<> struct DefaultPropatationMixerStruct<bool> { +template<> struct DefaultPropagationMixerStruct<bool> { using type = BooleanPropagationMixer; }; @@ -396,7 +479,7 @@ template<> struct DefaultPropatationMixerStruct<bool> { * (the default mixing for booleans). */ template<typename T> -using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type; +using DefaultPropagationMixer = typename DefaultPropagationMixerStruct<T>::type; /* Utility to get a good default mixer for a given type. This is `void` when there is no default * mixer for the given type. */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 2067730faca..ee9c7a964d9 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -17,15 +17,15 @@ extern "C" { */ /* Blender major and minor version. */ -#define BLENDER_VERSION 303 +#define BLENDER_VERSION 304 /* 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 6 +#define BLENDER_FILE_SUBVERSION 0 /* 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_displist.h b/source/blender/blenkernel/BKE_displist.h index 7a21e85e310..cdca740555a 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -61,7 +61,6 @@ typedef struct DispList { int totindex; /* indexed array drawing surfaces */ } DispList; -void BKE_displist_copy(struct ListBase *lbn, const struct ListBase *lb); DispList *BKE_displist_find(struct ListBase *lb, int type); void BKE_displist_normals_add(struct ListBase *lb); void BKE_displist_count(const struct ListBase *lb, int *totvert, int *totface, int *tottri); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 404ce63a5df..c14da538e7c 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -7,6 +7,7 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #ifdef __cplusplus extern "C" { diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh index 1e741cc252f..6a42ab1669f 100644 --- a/source/blender/blenkernel/BKE_idprop.hh +++ b/source/blender/blenkernel/BKE_idprop.hh @@ -45,6 +45,9 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, d std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, const StringRefNull value); +/** \brief Allocate a new IDProperty of type IDP_ID, set its name and value. */ +std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, ID *id); + /** * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT. * diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 2db8f75770a..eb43ce823ac 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -366,14 +366,7 @@ bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile); void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number); void BKE_image_sort_tiles(struct Image *ima); -bool BKE_image_fill_tile(struct Image *ima, - struct ImageTile *tile, - int width, - int height, - const float color[4], - int gen_type, - int planes, - bool is_float); +bool BKE_image_fill_tile(struct Image *ima, struct ImageTile *tile); typedef enum { UDIM_TILE_FORMAT_NONE = 0, @@ -425,13 +418,13 @@ int BKE_image_get_tile_from_pos(struct Image *ima, void BKE_image_get_tile_uv(const struct Image *ima, const int tile_number, float r_uv[2]); /** - * Return the tile_number for the closest UDIM tile. + * Return the tile_number for the closest UDIM tile to `co`. */ int BKE_image_find_nearest_tile_with_offset(const struct Image *image, const float co[2], - float r_uv_offset[2]) ATTR_NONNULL(1, 2, 3); + float r_uv_offset[2]) ATTR_NONNULL(2, 3); int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]) - ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; + ATTR_NONNULL(2) ATTR_WARN_UNUSED_RESULT; void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height); void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r_size[2]); diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 94497d9a487..148e6ec2791 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -453,6 +453,11 @@ struct ID *BKE_id_copy_for_duplicate(struct Main *bmain, uint duplicate_flags, int copy_flags); +/* Special version of BKE_id_copy which is safe from using evaluated id as source with a copy + * result appearing in the main database. + * Takes care of the referenced data-blocks consistency. */ +struct ID *BKE_id_copy_for_use_in_bmain(struct Main *bmain, const struct ID *id); + /** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 9ad5a32e6f0..f933946164c 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -60,7 +60,7 @@ void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user); /** - * Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the acutal ID owning + * Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the actual ID owning * it. * * \note This is especially useful when `id` is a non-real override (e.g. embedded ID like a master diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index c58bcbea242..44588a06119 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -17,11 +17,10 @@ struct MLoopUV; struct MPoly; struct MVert; -/* map from uv vertex to face (for select linked, stitch, uv suburf) */ - /* UvVertMap */ #define STD_UV_CONNECT_LIMIT 0.0001f +/* Map from uv vertex to face. Used by select linked, uv subsurf and obj exporter. */ typedef struct UvVertMap { struct UvMapVert **vert; struct UvMapVert *buf; @@ -52,17 +51,26 @@ typedef struct UvElement { unsigned int island; } UvElement; -/* UvElementMap is a container for UvElements of a mesh. It stores some UvElements belonging to the - * same uv island in sequence and the number of uvs per island so it is possible to access all uvs - * belonging to an island directly by iterating through the buffer. +/** UvElementMap is a container for UvElements of a BMesh. + * + * It simplifies access to UV information and ensures the + * different UV selection modes are respected. + * + * If islands are calculated, it also stores UvElements + * belonging to the same uv island in sequence and + * the number of uvs per island. */ typedef struct UvElementMap { - /* address UvElements by their vertex */ - struct UvElement **vert; - /* UvElement Store */ - struct UvElement *buf; - /* Total number of UVs in the layer. Useful to know */ - int totalUVs; + /** UvElement Storage. */ + struct UvElement *storage; + /** Total number of UVs. */ + int total_uvs; + /** Total number of unique UVs. */ + int total_unique_uvs; + + /* If Non-NULL, address UvElements by `BM_elem_index_get(BMVert*)`. */ + struct UvElement **vertex; + /* Number of Islands in the mesh */ int totalIslands; /* Stores the starting index in buf where each island begins */ diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh index 0b7d1a1835f..fb01083f334 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.hh +++ b/source/blender/blenkernel/BKE_mesh_sample.hh @@ -13,7 +13,6 @@ #include "DNA_meshdata_types.h" #include "BKE_attribute.h" -#include "BKE_attribute.hh" struct Mesh; struct BVHTreeFromMesh; @@ -27,22 +26,22 @@ namespace blender::bke::mesh_surface_sample { void sample_point_attribute(const Mesh &mesh, Span<int> looptri_indices, Span<float3> bary_coords, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); void sample_corner_attribute(const Mesh &mesh, Span<int> looptri_indices, Span<float3> bary_coords, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); void sample_face_attribute(const Mesh &mesh, Span<int> looptri_indices, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); enum class eAttributeMapMode { INTERPOLATED, @@ -57,7 +56,6 @@ enum class eAttributeMapMode { * these are computed lazily when needed and re-used. */ class MeshAttributeInterpolator { - private: const Mesh *mesh_; const IndexMask mask_; const Span<float3> positions_; @@ -68,18 +66,14 @@ class MeshAttributeInterpolator { public: MeshAttributeInterpolator(const Mesh *mesh, - const IndexMask mask, - const Span<float3> positions, - const Span<int> looptri_indices); + IndexMask mask, + Span<float3> positions, + Span<int> looptri_indices); void sample_data(const GVArray &src, eAttrDomain domain, eAttributeMapMode mode, - const GMutableSpan dst); - - void sample_attribute(const GAttributeReader &src_attribute, - GSpanAttributeWriter &dst_attribute, - eAttributeMapMode mode); + GMutableSpan dst); protected: Span<float3> ensure_barycentric_coords(); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 90dbec7ec52..02e3cefe6a5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -374,6 +374,9 @@ typedef struct bNodeTreeType { int type; /* type identifier */ char idname[64]; /* identifier name */ + /* The ID name of group nodes for this type. */ + char group_idname[64]; + char ui_name[64]; char ui_description[256]; int ui_icon; diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 162459d2005..8b9deadc960 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -13,6 +13,7 @@ #include "DNA_object_enums.h" #include "BKE_attribute.h" +#include "BKE_pbvh.h" #ifdef __cplusplus extern "C" { @@ -397,7 +398,7 @@ typedef struct SculptVertexInfo { typedef struct SculptBoundaryEditInfo { /* Vertex index from where the topology propagation reached this vertex. */ - int original_vertex; + int original_vertex_i; /* How many steps were needed to reach this vertex from the boundary. */ int num_propagation_steps; @@ -408,13 +409,14 @@ typedef struct SculptBoundaryEditInfo { /* Edge for drawing the boundary preview in the cursor. */ typedef struct SculptBoundaryPreviewEdge { - int v1; - int v2; + PBVHVertRef v1; + PBVHVertRef v2; } SculptBoundaryPreviewEdge; typedef struct SculptBoundary { /* Vertex indices of the active boundary. */ - int *vertices; + PBVHVertRef *vertices; + int *vertices_i; int vertices_capacity; int num_vertices; @@ -432,12 +434,13 @@ typedef struct SculptBoundary { bool forms_loop; /* Initial vertex in the boundary which is closest to the current sculpt active vertex. */ - int initial_vertex; + PBVHVertRef initial_vertex; + int initial_vertex_i; /* Vertex that at max_propagation_steps from the boundary and closest to the original active * vertex that was used to initialize the boundary. This is used as a reference to check how much * the deformation will go into the mesh and to calculate the strength of the brushes. */ - int pivot_vertex; + PBVHVertRef pivot_vertex; /* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed * during the brush action. This allows to use them as a reference positions and vectors for some @@ -565,7 +568,7 @@ typedef struct SculptSession { struct ExpandCache *expand_cache; /* Cursor data and active vertex for tools */ - int active_vertex_index; + PBVHVertRef active_vertex; int active_face_index; int active_grid_index; @@ -591,8 +594,8 @@ typedef struct SculptSession { struct Scene *scene; /* Dynamic mesh preview */ - int *preview_vert_index_list; - int preview_vert_index_count; + PBVHVertRef *preview_vert_list; + int preview_vert_count; /* Pose Brush Preview */ float pose_origin[3]; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 5641ff0ba34..af7effe806c 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -8,8 +8,11 @@ */ #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_ghash.h" +#include "bmesh.h" + /* For embedding CCGKey in iterator. */ #include "BKE_attribute.h" #include "BKE_ccg.h" @@ -43,6 +46,41 @@ struct MeshElemMap; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; +typedef enum { + PBVH_FACES, + PBVH_GRIDS, + PBVH_BMESH, +} PBVHType; + +/* Public members of PBVH, used for inlined functions. */ +struct PBVHPublic { + PBVHType type; + BMesh *bm; +}; + +/* + * These structs represent logical verts/edges/faces. + * for PBVH_GRIDS and PBVH_FACES they store integer + * offsets, PBVH_BMESH stores pointers. + * + * The idea is to enforce stronger type checking by encapsulating + * intptr_t's in structs. + */ + +typedef struct PBVHVertRef { + intptr_t i; +} PBVHVertRef; + +typedef struct PBVHEdgeRef { + intptr_t i; +} PBVHEdgeRef; + +typedef struct PBVHFaceRef { + intptr_t i; +} PBVHFaceRef; + +#define PBVH_REF_NONE -1LL + typedef struct { float (*co)[3]; } PBVHProxyNode; @@ -87,9 +125,97 @@ typedef struct PBVHFrustumPlanes { int num_planes; } PBVHFrustumPlanes; +BLI_INLINE PBVHType BKE_pbvh_type(const PBVH *pbvh) +{ + return ((const struct PBVHPublic *)pbvh)->type; +} + +BLI_INLINE BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) +{ + return ((struct PBVHPublic *)pbvh)->bm; +} + void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); +BLI_INLINE PBVHVertRef BKE_pbvh_make_vref(intptr_t i) +{ + PBVHVertRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_make_eref(intptr_t i) +{ + PBVHEdgeRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_make_fref(intptr_t i) +{ + PBVHFaceRef ret = {i}; + return ret; +} + +BLI_INLINE int BKE_pbvh_vertex_to_index(PBVH *pbvh, PBVHVertRef v) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != PBVH_REF_NONE ? + BM_elem_index_get((BMVert *)(v.i)) : + (v.i)); +} + +BLI_INLINE PBVHVertRef BKE_pbvh_index_to_vertex(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_vref(index); + case PBVH_BMESH: + return BKE_pbvh_make_vref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->vtable[index]); + } + + return BKE_pbvh_make_vref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_edge_to_index(PBVH *pbvh, PBVHEdgeRef e) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && e.i != PBVH_REF_NONE ? + BM_elem_index_get((BMEdge *)(e.i)) : + (e.i)); +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_index_to_edge(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_eref(index); + case PBVH_BMESH: + return BKE_pbvh_make_eref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->etable[index]); + } + + return BKE_pbvh_make_eref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_face_to_index(PBVH *pbvh, PBVHFaceRef f) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && f.i != PBVH_REF_NONE ? + BM_elem_index_get((BMFace *)(f.i)) : + (f.i)); +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_index_to_face(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_fref(index); + case PBVH_BMESH: + return BKE_pbvh_make_fref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->ftable[index]); + } + + return BKE_pbvh_make_fref(PBVH_REF_NONE); +} + /* Callbacks */ /** @@ -181,7 +307,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal); @@ -230,13 +356,7 @@ void BKE_pbvh_draw_debug_cb( void *user_data); /* PBVH Access */ -typedef enum { - PBVH_FACES, - PBVH_GRIDS, - PBVH_BMESH, -} PBVHType; -PBVHType BKE_pbvh_type(const PBVH *pbvh); bool BKE_pbvh_has_faces(const PBVH *pbvh); /** @@ -272,7 +392,6 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh); /** * Only valid for type == #PBVH_BMESH. */ -struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); typedef enum { @@ -308,7 +427,7 @@ void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked); bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node); void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh); -void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, int index); +void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, PBVHVertRef vertex); void BKE_pbvh_node_get_grids(PBVH *pbvh, PBVHNode *node, @@ -399,6 +518,7 @@ typedef struct PBVHVertexIter { int gy; int i; int index; + PBVHVertRef vertex; bool respect_hide; /* grid */ @@ -443,7 +563,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m if (vi.grids) { \ vi.width = vi.gridsize; \ vi.height = vi.gridsize; \ - vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ + vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ vi.grid = vi.grids[vi.grid_indices[vi.g]]; \ if (mode == PBVH_ITER_UNIQUE) { \ vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \ @@ -462,6 +582,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \ vi.grid = CCG_elem_next(&vi.key, vi.grid); \ vi.index++; \ + vi.vertex.i++; \ vi.visible = true; \ if (vi.gh) { \ if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \ @@ -482,7 +603,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.mvert->co; \ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \ - vi.index = vi.vert_indices[vi.i]; \ + vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \ if (vi.vmask) { \ vi.mask = &vi.vmask[vi.index]; \ } \ @@ -502,6 +623,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.bm_vert->co; \ vi.fno = vi.bm_vert->no; \ + vi.vertex = BKE_pbvh_make_vref((intptr_t)vi.bm_vert); \ vi.index = BM_elem_index_get(vi.bm_vert); \ vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \ } @@ -581,8 +703,8 @@ void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop); void BKE_pbvh_update_active_vcol(PBVH *pbvh, const struct Mesh *mesh); void BKE_pbvh_pmap_set(PBVH *pbvh, const struct MeshElemMap *pmap); -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]); -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]); +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]); +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]); void BKE_pbvh_ensure_node_loops(PBVH *pbvh); bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 3922bfb6c0d..a24a3e05dab 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -291,7 +291,7 @@ enum { /* Draw an item in the uiList */ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout, struct PointerRNA *dataptr, struct PointerRNA *itemptr, @@ -303,12 +303,12 @@ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, /* Draw the filtering part of an uiList */ typedef void (*uiListDrawFilterFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout); /* Filter items of an uiList */ typedef void (*uiListFilterItemsFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct PointerRNA *, const char *propname); diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 767018ae0bb..27542aa3586 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -360,7 +360,7 @@ class BezierSpline final : public Spline { * Returns non-owning access to an array of values containing the information necessary to * interpolate values from the original control points to evaluated points. The control point * index is the integer part of each value, and the factor used for interpolating to the next - * control point is the remaining factional part. + * control point is the remaining fractional part. */ blender::Span<float> evaluated_mappings() const; blender::Span<blender::float3> evaluated_positions() const final; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 2db4c086e04..6d7aed239e7 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -288,7 +288,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data, int max_seg_idx = BKE_anim_path_get_array_size(cache) - 1; /* Make an initial guess of where our intersection point will be. - * If the curve was a straight line, then the faction passed in r_new_curve_pos + * If the curve was a straight line, then the fraction passed in r_new_curve_pos * would be the correct location. * So make it our first initial guess. */ diff --git a/source/blender/blenkernel/intern/attribute_math.cc b/source/blender/blenkernel/intern/attribute_math.cc index c38df2a2969..d8102b4eeb8 100644 --- a/source/blender/blenkernel/intern/attribute_math.cc +++ b/source/blender/blenkernel/intern/attribute_math.cc @@ -4,13 +4,31 @@ namespace blender::attribute_math { -ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> output_buffer, +ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, ColorGeometry4f default_color) - : buffer_(output_buffer), - default_color_(default_color), - total_weights_(output_buffer.size(), 0.0f) + : ColorGeometry4fMixer(buffer, buffer.index_range(), default_color) +{ +} + +ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, + const IndexMask mask, + const ColorGeometry4f default_color) + : buffer_(buffer), default_color_(default_color), total_weights_(buffer.size(), 0.0f) { - buffer_.fill(ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + const ColorGeometry4f zero{0.0f, 0.0f, 0.0f, 0.0f}; + mask.foreach_index([&](const int64_t i) { buffer_[i] = zero; }); +} + +void ColorGeometry4fMixer::set(const int64_t index, + const ColorGeometry4f &color, + const float weight) +{ + BLI_assert(weight >= 0.0f); + buffer_[index].r = color.r * weight; + buffer_[index].g = color.g * weight; + buffer_[index].b = color.b * weight; + buffer_[index].a = color.a * weight; + total_weights_[index] = weight; } void ColorGeometry4fMixer::mix_in(const int64_t index, @@ -28,7 +46,12 @@ void ColorGeometry4fMixer::mix_in(const int64_t index, void ColorGeometry4fMixer::finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); +} + +void ColorGeometry4fMixer::finalize(const IndexMask mask) +{ + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; ColorGeometry4f &output_color = buffer_[i]; if (weight > 0.0f) { @@ -41,16 +64,37 @@ void ColorGeometry4fMixer::finalize() else { output_color = default_color_; } - } + }); } ColorGeometry4bMixer::ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, - ColorGeometry4b default_color) + const ColorGeometry4b default_color) + : ColorGeometry4bMixer(buffer, buffer.index_range(), default_color) +{ +} + +ColorGeometry4bMixer::ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, + const IndexMask mask, + const ColorGeometry4b default_color) : buffer_(buffer), default_color_(default_color), total_weights_(buffer.size(), 0.0f), accumulation_buffer_(buffer.size(), float4(0, 0, 0, 0)) { + const ColorGeometry4b zero{0, 0, 0, 0}; + mask.foreach_index([&](const int64_t i) { buffer_[i] = zero; }); +} + +void ColorGeometry4bMixer::ColorGeometry4bMixer::set(int64_t index, + const ColorGeometry4b &color, + const float weight) +{ + BLI_assert(weight >= 0.0f); + accumulation_buffer_[index][0] = color.r * weight; + accumulation_buffer_[index][1] = color.g * weight; + accumulation_buffer_[index][2] = color.b * weight; + accumulation_buffer_[index][3] = color.a * weight; + total_weights_[index] = weight; } void ColorGeometry4bMixer::mix_in(int64_t index, const ColorGeometry4b &color, float weight) @@ -66,7 +110,12 @@ void ColorGeometry4bMixer::mix_in(int64_t index, const ColorGeometry4b &color, f void ColorGeometry4bMixer::finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); +} + +void ColorGeometry4bMixer::finalize(const IndexMask mask) +{ + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; const float4 &accum_value = accumulation_buffer_[i]; ColorGeometry4b &output_color = buffer_[i]; @@ -80,7 +129,7 @@ void ColorGeometry4bMixer::finalize() else { output_color = default_color_; } - } + }); } } // namespace blender::attribute_math diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 09085fa8ffb..934c3053a02 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -713,7 +713,8 @@ void BKE_collection_new_name_get(Collection *collection_parent, char *rname) name = BLI_strdup(DATA_("Collection")); } else if (collection_parent->flag & COLLECTION_IS_MASTER) { - name = BLI_sprintfN(DATA_("Collection %d"), BLI_listbase_count(&collection_parent->children) + 1); + name = BLI_sprintfN(DATA_("Collection %d"), + BLI_listbase_count(&collection_parent->children) + 1); } else { const int number = BLI_listbase_count(&collection_parent->children) + 1; diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 8d4b64da817..fdd269bd9c8 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -73,7 +73,7 @@ static void set_crazy_vertex_quat(float r_quat[4], static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) { bool disabled = false; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); for (int i = 0; md && i <= cageIndex; i++, md = md->next) { @@ -241,7 +241,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra Mesh *me_input = static_cast<Mesh *>(ob->data); Mesh *me = nullptr; int i, a, modifiers_left_num = 0, verts_num = 0; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); float(*defmats)[3][3] = nullptr, (*deformedVerts)[3] = nullptr; VirtualModifierData virtualModifierData; ModifierEvalContext mectx = {depsgraph, ob, ModifierApplyFlag(0)}; @@ -362,7 +362,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); - MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); + MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, false); const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; const bool has_multires = mmd != nullptr && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, ModifierApplyFlag(0)}; diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc index 3ab6fb01ea5..62d5682da0f 100644 --- a/source/blender/blenkernel/intern/curve_nurbs.cc +++ b/source/blender/blenkernel/intern/curve_nurbs.cc @@ -4,8 +4,9 @@ * \ingroup bke */ -#include "BKE_attribute_math.hh" +#include "BLI_task.hh" +#include "BKE_attribute_math.hh" #include "BKE_curves.hh" namespace blender::bke::curves::nurbs { @@ -192,16 +193,16 @@ static void interpolate_to_evaluated(const BasisCache &basis_cache, { attribute_math::DefaultMixer<T> mixer{dst}; - for (const int i : dst.index_range()) { - Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); - - for (const int j : point_weights.index_range()) { - const int point_index = (basis_cache.start_indices[i] + j) % src.size(); - mixer.mix_in(i, src[point_index], point_weights[j]); + threading::parallel_for(dst.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); + for (const int j : point_weights.index_range()) { + const int point_index = (basis_cache.start_indices[i] + j) % src.size(); + mixer.mix_in(i, src[point_index], point_weights[j]); + } } - } - - mixer.finalize(); + mixer.finalize(range); + }); } template<typename T> @@ -213,17 +214,18 @@ static void interpolate_to_evaluated_rational(const BasisCache &basis_cache, { attribute_math::DefaultMixer<T> mixer{dst}; - for (const int i : dst.index_range()) { - Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); + threading::parallel_for(dst.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); - for (const int j : point_weights.index_range()) { - const int point_index = (basis_cache.start_indices[i] + j) % src.size(); - const float weight = point_weights[j] * control_weights[point_index]; - mixer.mix_in(i, src[point_index], weight); + for (const int j : point_weights.index_range()) { + const int point_index = (basis_cache.start_indices[i] + j) % src.size(); + const float weight = point_weights[j] * control_weights[point_index]; + mixer.mix_in(i, src[point_index], weight); + } } - } - - mixer.finalize(); + mixer.finalize(range); + }); } void interpolate_to_evaluated(const BasisCache &basis_cache, diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 6486be4afe0..c37634b5d3d 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -13,6 +13,7 @@ #include "BLI_index_mask_ops.hh" #include "BLI_length_parameterize.hh" #include "BLI_math_rotation.hh" +#include "BLI_task.hh" #include "DNA_curves_types.h" @@ -1163,6 +1164,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, } CurvesGeometry new_curves{new_point_count, new_curve_count}; + Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT); + Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE); threading::parallel_invoke( 256 < new_point_count * new_curve_count, @@ -1170,8 +1175,7 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); }, [&]() { /* Copy over point attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) { + for (bke::AttributeTransferData &attribute : point_attributes) { threading::parallel_for(copy_point_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { const IndexRange src_range = copy_point_ranges[range_i]; @@ -1182,24 +1186,29 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, {copy_point_range_dst_offsets[range_i], src_range.size()}); } }); - attribute.dst.finish(); } - + }, + [&]() { /* Copy over curve attributes. * In some cases points are just dissolved, so the the number of * curves will be the same. That could be optimized in the future. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) { + for (bke::AttributeTransferData &attribute : curve_attributes) { if (new_curves.curves_num() == curves.curves_num()) { attribute.dst.span.copy_from(attribute.src); } else { copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span); } - attribute.dst.finish(); } }); + for (bke::AttributeTransferData &attribute : point_attributes) { + attribute.dst.finish(); + } + for (bke::AttributeTransferData &attribute : curve_attributes) { + attribute.dst.finish(); + } + return new_curves; } @@ -1236,6 +1245,10 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, } CurvesGeometry new_curves{new_tot_points, new_tot_curves}; + Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT); + Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE); threading::parallel_invoke( 256 < new_tot_points * new_tot_curves, @@ -1267,8 +1280,7 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, }, [&]() { /* Copy over point attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) { + for (bke::AttributeTransferData &attribute : point_attributes) { threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { copy_between_buffers(attribute.src.type(), @@ -1278,11 +1290,11 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, new_point_ranges[range_i]); } }); - attribute.dst.finish(); } + }, + [&]() { /* Copy over curve attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) { + for (bke::AttributeTransferData &attribute : curve_attributes) { threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { copy_between_buffers(attribute.src.type(), @@ -1292,10 +1304,16 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, new_curve_ranges[range_i]); } }); - attribute.dst.finish(); } }); + for (bke::AttributeTransferData &attribute : point_attributes) { + attribute.dst.finish(); + } + for (bke::AttributeTransferData &attribute : curve_attributes) { + attribute.dst.finish(); + } + return new_curves; } @@ -1450,12 +1468,15 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves, MutableSpan<T> r_values) { attribute_math::DefaultMixer<T> mixer(r_values); - for (const int i_curve : IndexRange(curves.curves_num())) { - for (const int i_point : curves.points_for_curve(i_curve)) { - mixer.mix_in(i_curve, old_values[i_point]); + + threading::parallel_for(curves.curves_range(), 128, [&](const IndexRange range) { + for (const int i_curve : range) { + for (const int i_point : curves.points_for_curve(i_curve)) { + mixer.mix_in(i_curve, old_values[i_point]); + } } - } - mixer.finalize(); + mixer.finalize(range); + }); } /** diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 82356e06d2c..acb978642aa 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -165,7 +165,7 @@ struct LayerTypeInfo { void (*initminmax)(void *min, void *max); void (*add)(void *data1, const void *data2); void (*dominmax)(const void *data1, void *min, void *max); - void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor); + void (*copyvalue)(const void *source, void *dest, int mixmode, const float mixfactor); /** a function to read data from a cdf file */ bool (*read)(CDataFile *cdf, void *data, int count); @@ -187,7 +187,7 @@ struct LayerTypeInfo { /** \name Callbacks for (#MDeformVert, #CD_MDEFORMVERT) * \{ */ -static void layerCopy_mdeformvert(const void *source, void *dest, int count) +static void layerCopy_mdeformvert(const void *source, void *dest, const int count) { int i, size = sizeof(MDeformVert); @@ -209,7 +209,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count) } } -static void layerFree_mdeformvert(void *data, int count, int size) +static void layerFree_mdeformvert(void *data, const int count, const int size) { for (int i = 0; i < count; i++) { MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size)); @@ -222,38 +222,10 @@ static void layerFree_mdeformvert(void *data, int count, int size) } } -/* copy just zeros in this case */ -static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count) -{ - const int size = sizeof(void *); - - for (int i = 0; i < count; i++) { - void **ptr = (void **)POINTER_OFFSET(dest, i * size); - *ptr = nullptr; - } -} - -#ifndef WITH_PYTHON -void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self)) -{ - /* dummy */ -} -#endif - -static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size) -{ - for (int i = 0; i < count; i++) { - void **ptr = (void **)POINTER_OFFSET(data, i * size); - if (*ptr) { - bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); - } - } -} - static void layerInterp_mdeformvert(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { /* a single linked list of MDeformWeight's @@ -347,7 +319,7 @@ static void layerInterp_mdeformvert(const void **sources, static void layerInterp_normal(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { /* NOTE: This is linear interpolation, which is not optimal for vectors. @@ -355,8 +327,8 @@ static void layerInterp_normal(const void **sources, * so for now it will do... */ float no[3] = {0.0f}; - while (count--) { - madd_v3_v3fl(no, (const float *)sources[count], weights[count]); + for (const int i : IndexRange(count)) { + madd_v3_v3fl(no, (const float *)sources[i], weights[i]); } /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */ @@ -406,7 +378,7 @@ static void layerCopyValue_normal(const void *source, /** \name Callbacks for (#MTFace, #CD_MTFACE) * \{ */ -static void layerCopy_tface(const void *source, void *dest, int count) +static void layerCopy_tface(const void *source, void *dest, const int count) { const MTFace *source_tf = (const MTFace *)source; MTFace *dest_tf = (MTFace *)dest; @@ -415,8 +387,11 @@ static void layerCopy_tface(const void *source, void *dest, int count) } } -static void layerInterp_tface( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_tface(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { MTFace *tf = static_cast<MTFace *>(dest); float uv[4][2] = {{0.0f}}; @@ -456,7 +431,7 @@ static void layerSwap_tface(void *data, const int *corner_indices) memcpy(tf->uv, uv, sizeof(tf->uv)); } -static void layerDefault_tface(void *data, int count) +static void layerDefault_tface(void *data, const int count) { static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; MTFace *tf = (MTFace *)data; @@ -477,7 +452,7 @@ static int layerMaxNum_tface() /** \name Callbacks for (#MFloatProperty, #CD_PROP_FLOAT) * \{ */ -static void layerCopy_propFloat(const void *source, void *dest, int count) +static void layerCopy_propFloat(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MFloatProperty) * count); } @@ -485,7 +460,7 @@ static void layerCopy_propFloat(const void *source, void *dest, int count) static void layerInterp_propFloat(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { float result = 0.0f; @@ -520,7 +495,7 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool /** \name Callbacks for (#MIntProperty, #CD_PROP_INT32) * \{ */ -static void layerCopy_propInt(const void *source, void *dest, int count) +static void layerCopy_propInt(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MIntProperty) * count); } @@ -528,7 +503,7 @@ static void layerCopy_propInt(const void *source, void *dest, int count) static void layerInterp_propInt(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { float result = 0.0f; @@ -547,7 +522,7 @@ static void layerInterp_propInt(const void **sources, /** \name Callbacks for (#MStringProperty, #CD_PROP_STRING) * \{ */ -static void layerCopy_propString(const void *source, void *dest, int count) +static void layerCopy_propString(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MStringProperty) * count); } @@ -558,7 +533,7 @@ static void layerCopy_propString(const void *source, void *dest, int count) /** \name Callbacks for (#OrigSpaceFace, #CD_ORIGSPACE) * \{ */ -static void layerCopy_origspace_face(const void *source, void *dest, int count) +static void layerCopy_origspace_face(const void *source, void *dest, const int count) { const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source; OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest; @@ -568,8 +543,11 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count) } } -static void layerInterp_origspace_face( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_origspace_face(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest); float uv[4][2] = {{0.0f}}; @@ -606,7 +584,7 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices) memcpy(osf->uv, uv, sizeof(osf->uv)); } -static void layerDefault_origspace_face(void *data, int count) +static void layerDefault_origspace_face(void *data, const int count) { static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; OrigSpaceFace *osf = (OrigSpaceFace *)data; @@ -652,7 +630,7 @@ static void layerSwap_mdisps(void *data, const int *ci) } } -static void layerCopy_mdisps(const void *source, void *dest, int count) +static void layerCopy_mdisps(const void *source, void *dest, const int count) { const MDisps *s = static_cast<const MDisps *>(source); MDisps *d = static_cast<MDisps *>(dest); @@ -673,7 +651,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count) } } -static void layerFree_mdisps(void *data, int count, int UNUSED(size)) +static void layerFree_mdisps(void *data, const int count, const int UNUSED(size)) { MDisps *d = static_cast<MDisps *>(data); @@ -691,7 +669,7 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size)) } } -static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) +static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count) { MDisps *d = static_cast<MDisps *>(data); @@ -709,7 +687,7 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) return true; } -static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) +static bool layerWrite_mdisps(CDataFile *cdf, const void *data, const int count) { const MDisps *d = static_cast<const MDisps *>(data); @@ -723,7 +701,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) return true; } -static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count) +static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, const int count) { const MDisps *d = static_cast<const MDisps *>(data); size_t size = 0; @@ -738,6 +716,40 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int /** \} */ /* -------------------------------------------------------------------- */ +/** \name Callbacks for (#CD_BM_ELEM_PYPTR) + * \{ */ + +/* copy just zeros in this case */ +static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, const int count) +{ + const int size = sizeof(void *); + + for (int i = 0; i < count; i++) { + void **ptr = (void **)POINTER_OFFSET(dest, i * size); + *ptr = nullptr; + } +} + +#ifndef WITH_PYTHON +void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self)) +{ + /* dummy */ +} +#endif + +static void layerFree_bmesh_elem_py_ptr(void *data, const int count, const int size) +{ + for (int i = 0; i < count; i++) { + void **ptr = (void **)POINTER_OFFSET(data, i * size); + if (*ptr) { + bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Callbacks for (`float`, #CD_PAINT_MASK) * \{ */ @@ -762,7 +774,7 @@ static void layerInterp_paint_mask(const void **sources, /** \name Callbacks for (#GridPaintMask, #CD_GRID_PAINT_MASK) * \{ */ -static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) +static void layerCopy_grid_paint_mask(const void *source, void *dest, const int count) { const GridPaintMask *s = static_cast<const GridPaintMask *>(source); GridPaintMask *d = static_cast<GridPaintMask *>(dest); @@ -779,7 +791,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) } } -static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) +static void layerFree_grid_paint_mask(void *data, const int count, const int UNUSED(size)) { GridPaintMask *gpm = static_cast<GridPaintMask *>(data); @@ -867,7 +879,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2) return r * r + g * g + b * b + a * a < 0.001f; } -static void layerMultiply_mloopcol(void *data, float fac) +static void layerMultiply_mloopcol(void *data, const float fac) { MLoopCol *m = static_cast<MLoopCol *>(data); @@ -936,7 +948,7 @@ static void layerInitMinMax_mloopcol(void *vmin, void *vmax) max->a = 0; } -static void layerDefault_mloopcol(void *data, int count) +static void layerDefault_mloopcol(void *data, const int count) { MLoopCol default_mloopcol = {255, 255, 255, 255}; MLoopCol *mlcol = (MLoopCol *)data; @@ -1016,7 +1028,7 @@ static bool layerEqual_mloopuv(const void *data1, const void *data2) return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } -static void layerMultiply_mloopuv(void *data, float fac) +static void layerMultiply_mloopuv(void *data, const float fac) { MLoopUV *luv = static_cast<MLoopUV *>(data); @@ -1110,7 +1122,7 @@ static bool layerEqual_mloop_origspace(const void *data1, const void *data2) return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } -static void layerMultiply_mloop_origspace(void *data, float fac) +static void layerMultiply_mloop_origspace(void *data, const float fac) { OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data); @@ -1162,8 +1174,11 @@ static void layerInterp_mloop_origspace(const void **sources, } /* --- end copy */ -static void layerInterp_mcol( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_mcol(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { MCol *mc = static_cast<MCol *>(dest); struct { @@ -1222,7 +1237,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices) memcpy(mcol, col, sizeof(col)); } -static void layerDefault_mcol(void *data, int count) +static void layerDefault_mcol(void *data, const int count) { static MCol default_mcol = {255, 255, 255, 255}; MCol *mcol = (MCol *)data; @@ -1232,7 +1247,7 @@ static void layerDefault_mcol(void *data, int count) } } -static void layerDefault_origindex(void *data, int count) +static void layerDefault_origindex(void *data, const int count) { copy_vn_i((int *)data, count, ORIGINDEX_NONE); } @@ -1290,7 +1305,7 @@ static void layerInterp_shapekey(const void **sources, /** \name Callbacks for (#MVertSkin, #CD_MVERT_SKIN) * \{ */ -static void layerDefault_mvert_skin(void *data, int count) +static void layerDefault_mvert_skin(void *data, const int count) { MVertSkin *vs = static_cast<MVertSkin *>(data); @@ -1300,7 +1315,7 @@ static void layerDefault_mvert_skin(void *data, int count) } } -static void layerCopy_mvert_skin(const void *source, void *dest, int count) +static void layerCopy_mvert_skin(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MVertSkin) * count); } @@ -1352,7 +1367,7 @@ static void layerSwap_flnor(void *data, const int *corner_indices) /** \name Callbacks for (`int`, #CD_FACEMAP) * \{ */ -static void layerDefault_fmap(void *data, int count) +static void layerDefault_fmap(void *data, const int count) { int *fmap_num = (int *)data; for (int i = 0; i < count; i++) { @@ -1428,7 +1443,7 @@ static bool layerEqual_propcol(const void *data1, const void *data2) return tot < 0.001f; } -static void layerMultiply_propcol(void *data, float fac) +static void layerMultiply_propcol(void *data, const float fac) { MPropCol *m = static_cast<MPropCol *>(data); mul_v4_fl(m->color, fac); @@ -1458,7 +1473,7 @@ static void layerInitMinMax_propcol(void *vmin, void *vmax) copy_v4_fl(max->color, FLT_MIN); } -static void layerDefault_propcol(void *data, int count) +static void layerDefault_propcol(void *data, const int count) { /* Default to white, full alpha. */ MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}}; @@ -1510,7 +1525,7 @@ static void layerInterp_propfloat3(const void **sources, copy_v3_v3((float *)dest, &result.x); } -static void layerMultiply_propfloat3(void *data, float fac) +static void layerMultiply_propfloat3(void *data, const float fac) { vec3f *vec = static_cast<vec3f *>(data); vec->x *= fac; @@ -1563,7 +1578,7 @@ static void layerInterp_propfloat2(const void **sources, copy_v2_v2((float *)dest, &result.x); } -static void layerMultiply_propfloat2(void *data, float fac) +static void layerMultiply_propfloat2(void *data, const float fac) { vec2f *vec = static_cast<vec2f *>(data); vec->x *= fac; @@ -2327,7 +2342,7 @@ bool CustomData_merge(const CustomData *source, return changed; } -void CustomData_realloc(CustomData *data, int totelem) +void CustomData_realloc(CustomData *data, const int totelem) { BLI_assert(totelem >= 0); for (int i = 0; i < data->totlayer; i++) { @@ -2358,7 +2373,7 @@ void CustomData_copy(const CustomData *source, CustomData_merge(source, dest, mask, alloctype, totelem); } -static void customData_free_layer__internal(CustomDataLayer *layer, int totelem) +static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) { const LayerTypeInfo *typeInfo; @@ -2393,7 +2408,7 @@ void CustomData_reset(CustomData *data) copy_vn_i(data->typemap, CD_NUMTYPES, -1); } -void CustomData_free(CustomData *data, int totelem) +void CustomData_free(CustomData *data, const int totelem) { for (int i = 0; i < data->totlayer; i++) { customData_free_layer__internal(&data->layers[i], totelem); @@ -2407,7 +2422,7 @@ void CustomData_free(CustomData *data, int totelem) CustomData_reset(data); } -void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask) +void CustomData_free_typemask(CustomData *data, const int totelem, eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -2442,7 +2457,7 @@ static void customData_update_offsets(CustomData *data) } /* to use when we're in the middle of modifying layers */ -static int CustomData_get_layer_index__notypemap(const CustomData *data, int type) +static int CustomData_get_layer_index__notypemap(const CustomData *data, const int type) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2456,13 +2471,13 @@ static int CustomData_get_layer_index__notypemap(const CustomData *data, int typ /* -------------------------------------------------------------------- */ /* index values to access the layers (offset from the layer start) */ -int CustomData_get_layer_index(const CustomData *data, int type) +int CustomData_get_layer_index(const CustomData *data, const int type) { BLI_assert(customdata_typemap_is_valid(data)); return data->typemap[type]; } -int CustomData_get_layer_index_n(const CustomData *data, int type, int n) +int CustomData_get_layer_index_n(const CustomData *data, const int type, const int n) { BLI_assert(n >= 0); int i = CustomData_get_layer_index(data, type); @@ -2475,7 +2490,7 @@ int CustomData_get_layer_index_n(const CustomData *data, int type, int n) return i; } -int CustomData_get_named_layer_index(const CustomData *data, int type, const char *name) +int CustomData_get_named_layer_index(const CustomData *data, const int type, const char *name) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2488,28 +2503,28 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha return -1; } -int CustomData_get_active_layer_index(const CustomData *data, int type) +int CustomData_get_active_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1; } -int CustomData_get_render_layer_index(const CustomData *data, int type) +int CustomData_get_render_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active_rnd : -1; } -int CustomData_get_clone_layer_index(const CustomData *data, int type) +int CustomData_get_clone_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active_clone : -1; } -int CustomData_get_stencil_layer_index(const CustomData *data, int type) +int CustomData_get_stencil_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2519,7 +2534,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type) /* -------------------------------------------------------------------- */ /* index values per layer type */ -int CustomData_get_named_layer(const CustomData *data, int type, const char *name) +int CustomData_get_named_layer(const CustomData *data, const int type, const char *name) { const int named_index = CustomData_get_named_layer_index(data, type, name); const int layer_index = data->typemap[type]; @@ -2527,28 +2542,28 @@ int CustomData_get_named_layer(const CustomData *data, int type, const char *nam return (named_index != -1) ? named_index - layer_index : -1; } -int CustomData_get_active_layer(const CustomData *data, int type) +int CustomData_get_active_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active : -1; } -int CustomData_get_render_layer(const CustomData *data, int type) +int CustomData_get_render_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active_rnd : -1; } -int CustomData_get_clone_layer(const CustomData *data, int type) +int CustomData_get_clone_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active_clone : -1; } -int CustomData_get_stencil_layer(const CustomData *data, int type) +int CustomData_get_stencil_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2562,7 +2577,7 @@ const char *CustomData_get_active_layer_name(const CustomData *data, const int t return layer_index < 0 ? nullptr : data->layers[layer_index].name; } -void CustomData_set_layer_active(CustomData *data, int type, int n) +void CustomData_set_layer_active(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2571,7 +2586,7 @@ void CustomData_set_layer_active(CustomData *data, int type, int n) } } -void CustomData_set_layer_render(CustomData *data, int type, int n) +void CustomData_set_layer_render(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2580,7 +2595,7 @@ void CustomData_set_layer_render(CustomData *data, int type, int n) } } -void CustomData_set_layer_clone(CustomData *data, int type, int n) +void CustomData_set_layer_clone(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2589,7 +2604,7 @@ void CustomData_set_layer_clone(CustomData *data, int type, int n) } } -void CustomData_set_layer_stencil(CustomData *data, int type, int n) +void CustomData_set_layer_stencil(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2598,7 +2613,7 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n) } } -void CustomData_set_layer_active_index(CustomData *data, int type, int n) +void CustomData_set_layer_active_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2610,7 +2625,7 @@ void CustomData_set_layer_active_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_render_index(CustomData *data, int type, int n) +void CustomData_set_layer_render_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2622,7 +2637,7 @@ void CustomData_set_layer_render_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_clone_index(CustomData *data, int type, int n) +void CustomData_set_layer_clone_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2634,7 +2649,7 @@ void CustomData_set_layer_clone_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_stencil_index(CustomData *data, int type, int n) +void CustomData_set_layer_stencil_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2646,7 +2661,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_flag(CustomData *data, int type, int flag) +void CustomData_set_layer_flag(CustomData *data, const int type, const int flag) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2655,7 +2670,7 @@ void CustomData_set_layer_flag(CustomData *data, int type, int flag) } } -void CustomData_clear_layer_flag(CustomData *data, int type, int flag) +void CustomData_clear_layer_flag(CustomData *data, const int type, const int flag) { const int nflag = ~flag; @@ -2666,7 +2681,7 @@ void CustomData_clear_layer_flag(CustomData *data, int type, int flag) } } -static bool customData_resize(CustomData *data, int amount) +static bool customData_resize(CustomData *data, const int amount) { CustomDataLayer *tmp = static_cast<CustomDataLayer *>( MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__)); @@ -2685,15 +2700,14 @@ static bool customData_resize(CustomData *data, int amount) } static CustomDataLayer *customData_add_layer__internal(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const char *name) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - int flag = 0, index = data->totlayer; - void *newlayerdata = nullptr; + int flag = 0; /* Passing a layer-data to copy from with an alloctype that won't copy is * most likely a bug */ @@ -2703,6 +2717,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, return &data->layers[CustomData_get_layer_index(data, type)]; } + void *newlayerdata = nullptr; if (ELEM(alloctype, CD_ASSIGN, CD_REFERENCE)) { newlayerdata = layerdata; } @@ -2738,6 +2753,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, flag |= CD_FLAG_NOFREE; } + int index = data->totlayer; if (index >= data->maxlayer) { if (!customData_resize(data, CUSTOMDATA_GROW)) { if (newlayerdata != layerdata) { @@ -2754,14 +2770,16 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, data->layers[index] = data->layers[index - 1]; } + CustomDataLayer &new_layer = data->layers[index]; + /* Clear remaining data on the layer. The original data on the layer has been moved to another * index. Without this, it can happen that information from the previous layer at that index * leaks into the new layer. */ - memset(data->layers + index, 0, sizeof(CustomDataLayer)); + memset(&new_layer, 0, sizeof(CustomDataLayer)); - data->layers[index].type = type; - data->layers[index].flag = flag; - data->layers[index].data = newlayerdata; + new_layer.type = type; + new_layer.flag = flag; + new_layer.data = newlayerdata; /* Set default name if none exists. Note we only call DATA_() once * we know there is a default name, to avoid overhead of locale lookups @@ -2771,24 +2789,24 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, } if (name) { - BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name)); + BLI_strncpy(new_layer.name, name, sizeof(new_layer.name)); CustomData_set_layer_unique_name(data, index); } else { - data->layers[index].name[0] = '\0'; + new_layer.name[0] = '\0'; } if (index > 0 && data->layers[index - 1].type == type) { - data->layers[index].active = data->layers[index - 1].active; - data->layers[index].active_rnd = data->layers[index - 1].active_rnd; - data->layers[index].active_clone = data->layers[index - 1].active_clone; - data->layers[index].active_mask = data->layers[index - 1].active_mask; + new_layer.active = data->layers[index - 1].active; + new_layer.active_rnd = data->layers[index - 1].active_rnd; + new_layer.active_clone = data->layers[index - 1].active_clone; + new_layer.active_mask = data->layers[index - 1].active_mask; } else { - data->layers[index].active = 0; - data->layers[index].active_rnd = 0; - data->layers[index].active_clone = 0; - data->layers[index].active_mask = 0; + new_layer.active = 0; + new_layer.active_rnd = 0; + new_layer.active_clone = 0; + new_layer.active_mask = 0; } customData_update_offsets(data); @@ -2797,7 +2815,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, } void *CustomData_add_layer( - CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem) + CustomData *data, const int type, eCDAllocType alloctype, void *layerdata, const int totelem) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2813,10 +2831,10 @@ void *CustomData_add_layer( } void *CustomData_add_layer_named(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const char *name) { CustomDataLayer *layer = customData_add_layer__internal( @@ -2831,10 +2849,10 @@ void *CustomData_add_layer_named(CustomData *data, } void *CustomData_add_layer_anonymous(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const AnonymousAttributeID *anonymous_id) { const char *name = BKE_anonymous_attribute_id_internal_name(anonymous_id); @@ -2851,7 +2869,7 @@ void *CustomData_add_layer_anonymous(CustomData *data, return layer->data; } -bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) +bool CustomData_free_layer(CustomData *data, const int type, const int totelem, const int index) { const int index_first = CustomData_get_layer_index(data, type); const int n = index - index_first; @@ -2915,7 +2933,7 @@ bool CustomData_free_layer_named(CustomData *data, const char *name, const int t return false; } -bool CustomData_free_layer_active(CustomData *data, int type, int totelem) +bool CustomData_free_layer_active(CustomData *data, const int type, const int totelem) { const int index = CustomData_get_active_layer_index(data, type); if (index == -1) { @@ -2924,7 +2942,7 @@ bool CustomData_free_layer_active(CustomData *data, int type, int totelem) return CustomData_free_layer(data, type, totelem, index); } -void CustomData_free_layers(CustomData *data, int type, int totelem) +void CustomData_free_layers(CustomData *data, const int type, const int totelem) { const int index = CustomData_get_layer_index(data, type); while (CustomData_free_layer(data, type, totelem, index)) { @@ -2932,12 +2950,12 @@ void CustomData_free_layers(CustomData *data, int type, int totelem) } } -bool CustomData_has_layer(const CustomData *data, int type) +bool CustomData_has_layer(const CustomData *data, const int type) { return (CustomData_get_layer_index(data, type) != -1); } -int CustomData_number_of_layers(const CustomData *data, int type) +int CustomData_number_of_layers(const CustomData *data, const int type) { int number = 0; @@ -2950,7 +2968,7 @@ int CustomData_number_of_layers(const CustomData *data, int type) return number; } -int CustomData_number_of_layers_typemask(const CustomData *data, eCustomDataMask mask) +int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDataMask mask) { int number = 0; @@ -3040,7 +3058,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data, return nullptr; } -void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) +void CustomData_duplicate_referenced_layers(CustomData *data, const int totelem) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -3048,7 +3066,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) } } -bool CustomData_is_referenced_layer(CustomData *data, int type) +bool CustomData_is_referenced_layer(CustomData *data, const int type) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3061,7 +3079,7 @@ bool CustomData_is_referenced_layer(CustomData *data, int type) return (layer->flag & CD_FLAG_NOFREE) != 0; } -void CustomData_free_temporary(CustomData *data, int totelem) +void CustomData_free_temporary(CustomData *data, const int totelem) { int i, j; bool changed = false; @@ -3093,7 +3111,7 @@ void CustomData_free_temporary(CustomData *data, int totelem) } } -void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask) +void CustomData_set_only_copy(const CustomData *data, const eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) { @@ -3102,7 +3120,10 @@ void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask) } } -void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count) +void CustomData_copy_elements(const int type, + void *src_data_ofs, + void *dst_data_ofs, + const int count) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3116,11 +3137,11 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, - int src_layer_index, - int dst_layer_index, - int src_index, - int dst_index, - int count) + const int src_layer_index, + const int dst_layer_index, + const int src_index, + const int dst_index, + const int count) { const LayerTypeInfo *typeInfo; @@ -3154,8 +3175,11 @@ void CustomData_copy_data_layer(const CustomData *source, } } -void CustomData_copy_data_named( - const CustomData *source, CustomData *dest, int source_index, int dest_index, int count) +void CustomData_copy_data_named(const CustomData *source, + CustomData *dest, + const int source_index, + const int dest_index, + const int count) { /* copies a layer at a time */ for (int src_i = 0; src_i < source->totlayer; src_i++) { @@ -3170,8 +3194,11 @@ void CustomData_copy_data_named( } } -void CustomData_copy_data( - const CustomData *source, CustomData *dest, int source_index, int dest_index, int count) +void CustomData_copy_data(const CustomData *source, + CustomData *dest, + const int source_index, + const int dest_index, + const int count) { /* copies a layer at a time */ int dest_i = 0; @@ -3226,7 +3253,7 @@ void CustomData_copy_layer_type_data(const CustomData *source, count); } -void CustomData_free_elem(CustomData *data, int index, int count) +void CustomData_free_elem(CustomData *data, const int index, const int count) { for (int i = 0; i < data->totlayer; i++) { if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { @@ -3326,7 +3353,7 @@ void CustomData_interp(const CustomData *source, } } -void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices) +void CustomData_swap_corners(CustomData *data, const int index, const int *corner_indices) { for (int i = 0; i < data->totlayer; i++) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); @@ -3366,7 +3393,7 @@ void CustomData_swap(CustomData *data, const int index_a, const int index_b) } } -void *CustomData_get(const CustomData *data, int index, int type) +void *CustomData_get(const CustomData *data, const int index, const int type) { BLI_assert(index >= 0); @@ -3382,7 +3409,7 @@ void *CustomData_get(const CustomData *data, int index, int type) return POINTER_OFFSET(data->layers[layer_index].data, offset); } -void *CustomData_get_n(const CustomData *data, int type, int index, int n) +void *CustomData_get_n(const CustomData *data, const int type, const int index, const int n) { BLI_assert(index >= 0 && n >= 0); @@ -3396,7 +3423,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n) return POINTER_OFFSET(data->layers[layer_index + n].data, offset); } -void *CustomData_get_layer(const CustomData *data, int type) +void *CustomData_get_layer(const CustomData *data, const int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3407,7 +3434,7 @@ void *CustomData_get_layer(const CustomData *data, int type) return data->layers[layer_index].data; } -void *CustomData_get_layer_n(const CustomData *data, int type, int n) +void *CustomData_get_layer_n(const CustomData *data, const int type, const int n) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3418,7 +3445,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n) return data->layers[layer_index].data; } -void *CustomData_get_layer_named(const CustomData *data, int type, const char *name) +void *CustomData_get_layer_named(const CustomData *data, const int type, const char *name) { int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { @@ -3428,7 +3455,7 @@ void *CustomData_get_layer_named(const CustomData *data, int type, const char *n return data->layers[layer_index].data; } -int CustomData_get_offset(const CustomData *data, int type) +int CustomData_get_offset(const CustomData *data, const int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3439,10 +3466,10 @@ int CustomData_get_offset(const CustomData *data, int type) return data->layers[layer_index].offset; } -int CustomData_get_offset_named(const CustomData *data, int type, const char *name) +int CustomData_get_n_offset(const CustomData *data, const int type, const int n) { /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_named_layer_index(data, type, name); + int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { return -1; } @@ -3450,10 +3477,9 @@ int CustomData_get_offset_named(const CustomData *data, int type, const char *na return data->layers[layer_index].offset; } -int CustomData_get_n_offset(const CustomData *data, int type, int n) +int CustomData_get_offset_named(const CustomData *data, int type, const char *name) { - /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); + int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { return -1; } @@ -3461,7 +3487,10 @@ int CustomData_get_n_offset(const CustomData *data, int type, int n) return data->layers[layer_index].offset; } -bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name) +bool CustomData_set_layer_name(const CustomData *data, + const int type, + const int n, + const char *name) { /* get the layer index of the first layer of type */ const int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3475,14 +3504,14 @@ bool CustomData_set_layer_name(const CustomData *data, int type, int n, const ch return true; } -const char *CustomData_get_layer_name(const CustomData *data, int type, int n) +const char *CustomData_get_layer_name(const CustomData *data, const int type, const int n) { const int layer_index = CustomData_get_layer_index_n(data, type, n); return (layer_index == -1) ? nullptr : data->layers[layer_index].name; } -void *CustomData_set_layer(const CustomData *data, int type, void *ptr) +void *CustomData_set_layer(const CustomData *data, const int type, void *ptr) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3496,7 +3525,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr) return ptr; } -void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr) +void *CustomData_set_layer_n(const CustomData *data, const int type, const int n, void *ptr) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3509,7 +3538,7 @@ void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr) return ptr; } -void CustomData_set(const CustomData *data, int index, int type, const void *source) +void CustomData_set(const CustomData *data, const int index, const int type, const void *source) { void *dest = CustomData_get(data, index, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3561,7 +3590,7 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) } } -void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) +void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char htype) { int chunksize; @@ -3763,7 +3792,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, } } -static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) +static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n) { int offset = data->layers[n].offset; const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); @@ -3858,7 +3887,7 @@ void CustomData_bmesh_copy_data(const CustomData *source, CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0); } -void *CustomData_bmesh_get(const CustomData *data, void *block, int type) +void *CustomData_bmesh_get(const CustomData *data, void *block, const int type) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3869,7 +3898,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type) return POINTER_OFFSET(block, data->layers[layer_index].offset); } -void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int n) +void *CustomData_bmesh_get_n(const CustomData *data, void *block, const int type, const int n) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index(data, type); @@ -3880,7 +3909,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int return POINTER_OFFSET(block, data->layers[layer_index + n].offset); } -void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) +void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, const int n) { if (n < 0 || n >= data->totlayer) { return nullptr; @@ -3889,7 +3918,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) return POINTER_OFFSET(block, data->layers[n].offset); } -bool CustomData_layer_has_math(const CustomData *data, int layer_n) +bool CustomData_layer_has_math(const CustomData *data, const int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -3901,7 +3930,7 @@ bool CustomData_layer_has_math(const CustomData *data, int layer_n) return false; } -bool CustomData_layer_has_interp(const CustomData *data, int layer_n) +bool CustomData_layer_has_interp(const CustomData *data, const int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -4022,7 +4051,7 @@ void CustomData_data_dominmax(int type, const void *data, void *min, void *max) } } -void CustomData_data_multiply(int type, void *data, float fac) +void CustomData_data_multiply(int type, void *data, const float fac) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4040,7 +4069,7 @@ void CustomData_data_add(int type, void *data1, const void *data2) } } -void CustomData_bmesh_set(const CustomData *data, void *block, int type, const void *source) +void CustomData_bmesh_set(const CustomData *data, void *block, const int type, const void *source) { void *dest = CustomData_bmesh_get(data, block, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4057,7 +4086,8 @@ void CustomData_bmesh_set(const CustomData *data, void *block, int type, const v } } -void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, const void *source) +void CustomData_bmesh_set_n( + CustomData *data, void *block, const int type, const int n, const void *source) { void *dest = CustomData_bmesh_get_n(data, block, type, n); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4074,7 +4104,7 @@ void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, cons } } -void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const void *source) +void CustomData_bmesh_set_layer_n(CustomData *data, void *block, const int n, const void *source) { void *dest = CustomData_bmesh_get_layer_n(data, block, n); const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); @@ -4328,7 +4358,7 @@ int CustomData_layertype_layers_max(const int type) return typeInfo->layers_max(); } -static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int index) +static bool cd_layer_find_dupe(CustomData *data, const char *name, const int type, const int index) { /* see if there is a duplicate */ for (int i = 0; i < data->totlayer; i++) { @@ -4363,7 +4393,7 @@ static bool customdata_unique_check(void *arg, const char *name) return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index); } -void CustomData_set_layer_unique_name(CustomData *data, int index) +void CustomData_set_layer_unique_name(CustomData *data, const int index) { CustomDataLayer *nlayer = &data->layers[index]; const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type); @@ -4408,7 +4438,7 @@ void CustomData_validate_layer_name(const CustomData *data, } } -bool CustomData_verify_versions(CustomData *data, int index) +bool CustomData_verify_versions(CustomData *data, const int index) { const LayerTypeInfo *typeInfo; CustomDataLayer *layer = &data->layers[index]; @@ -4567,7 +4597,7 @@ void CustomData_external_reload(CustomData *data, } } -void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, int totelem) +void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, const int totelem) { CustomDataExternal *external = data->external; CustomDataLayer *layer; @@ -4641,7 +4671,7 @@ void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, in } void CustomData_external_write( - CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free) + CustomData *data, ID *id, eCustomDataMask mask, const int totelem, const int free) { CustomDataExternal *external = data->external; int update = 0; @@ -4743,8 +4773,11 @@ void CustomData_external_write( cdf_free(cdf); } -void CustomData_external_add( - CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filepath) +void CustomData_external_add(CustomData *data, + ID *UNUSED(id), + const int type, + const int UNUSED(totelem), + const char *filepath) { CustomDataExternal *external = data->external; @@ -4768,7 +4801,7 @@ void CustomData_external_add( layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY; } -void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem) +void CustomData_external_remove(CustomData *data, ID *id, const int type, const int totelem) { CustomDataExternal *external = data->external; @@ -4792,7 +4825,7 @@ void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem) } } -bool CustomData_external_test(CustomData *data, int type) +bool CustomData_external_test(CustomData *data, const int type) { int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { @@ -5093,7 +5126,10 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, /** \name Custom Data IO * \{ */ -static void write_mdisps(BlendWriter *writer, int count, const MDisps *mdlist, int external) +static void write_mdisps(BlendWriter *writer, + const int count, + const MDisps *mdlist, + const int external) { if (mdlist) { BLO_write_struct_array(writer, MDisps, count, mdlist); @@ -5193,7 +5229,10 @@ void CustomData_blend_write(BlendWriter *writer, } } -static void blend_read_mdisps(BlendDataReader *reader, int count, MDisps *mdisps, int external) +static void blend_read_mdisps(BlendDataReader *reader, + const int count, + MDisps *mdisps, + const int external) { if (mdisps) { for (int i = 0; i < count; i++) { @@ -5235,7 +5274,7 @@ static void blend_read_paint_mask(BlendDataReader *reader, } } -void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) +void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int count) { BLO_read_data_address(reader, &data->layers); diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 17a74b5564a..be686635d3e 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -70,8 +70,6 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types, r_data_masks->lmask |= CD_MASK_MLOOPUV; } else if (cddata_type == CD_FAKE_LNOR) { - r_data_masks->vmask |= CD_MASK_NORMAL; - r_data_masks->pmask |= CD_MASK_NORMAL; r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; } } diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 823fce52b50..b1017a78e15 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -86,19 +86,6 @@ DispList *BKE_displist_find(ListBase *lb, int type) return nullptr; } -void BKE_displist_copy(ListBase *lbn, const ListBase *lb) -{ - BKE_displist_free(lbn); - - LISTBASE_FOREACH (const DispList *, dl, lb) { - DispList *dln = (DispList *)MEM_dupallocN(dl); - BLI_addtail(lbn, dln); - dln->verts = (float *)MEM_dupallocN(dl->verts); - dln->nors = (float *)MEM_dupallocN(dl->nors); - dln->index = (int *)MEM_dupallocN(dl->index); - } -} - void BKE_displist_normals_add(ListBase *lb) { float *vdata, *ndata, nor[3]; diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc index f549393fd12..a2f58baebf7 100644 --- a/source/blender/blenkernel/intern/idprop_create.cc +++ b/source/blender/blenkernel/intern/idprop_create.cc @@ -44,6 +44,14 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_n return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); } +std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, ID *value) +{ + IDPropertyTemplate prop_template{0}; + prop_template.id = value; + IDProperty *property = IDP_New(IDP_ID, &prop_template, prop_name.c_str()); + return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); +} + static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name, eIDPropertyType subtype, size_t array_len) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 78eaba44a08..d915a9db76c 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -627,6 +627,16 @@ void BKE_image_free_data(Image *ima) image_free_data(&ima->id); } +static ImageTile *imagetile_alloc(int tile_number) +{ + ImageTile *tile = MEM_cnew<ImageTile>("Image Tile"); + tile->tile_number = tile_number; + tile->gen_x = 1024; + tile->gen_y = 1024; + tile->gen_type = IMA_GENTYPE_GRID; + return tile; +} + /* only image block itself */ static void image_init(Image *ima, short source, short type) { @@ -641,8 +651,7 @@ static void image_init(Image *ima, short source, short type) ima->flag |= IMA_VIEW_AS_RENDER; } - ImageTile *tile = MEM_cnew<ImageTile>("Image Tiles"); - tile->tile_number = 1001; + ImageTile *tile = imagetile_alloc(1001); BLI_addtail(&ima->tiles, tile); if (type == IMA_TYPE_R_RESULT) { @@ -863,37 +872,89 @@ void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2 } } +/** Linear distance between #x and the unit interval. */ +static float distance_to_unit_interval(float x) +{ + /* The unit interval is between 0 and 1. + * Within the interval, return 0. + * Outside the interval, return the distance to the nearest boundary. + * Intuitively, the function looks like: + * \ | | / + * __\|___|/__ + * 0 1 + */ + + if (x <= 0.0f) { + return -x; /* Distance to left border. */ + } + if (x <= 1.0f) { + return 0.0f; /* Inside unit interval. */ + } + return x - 1.0f; /* Distance to right border. */ +} + +/** Distance squared between #co and the unit square with lower-left starting at #udim. */ +static float distance_squared_to_udim(const float co[2], const float udim[2]) +{ + float delta[2]; + sub_v2_v2v2(delta, co, udim); + delta[0] = distance_to_unit_interval(delta[0]); + delta[1] = distance_to_unit_interval(delta[1]); + return len_squared_v2(delta); +} + +static bool nearest_udim_tile_tie_break(const float best_dist_sq, + const float best_uv[2], + const float dist_sq, + const float uv[2]) +{ + if (best_dist_sq == dist_sq) { /* Exact same distance? Tie-break. */ + if (best_uv[0] == uv[0]) { /* Exact same U? Tie-break. */ + return (uv[1] > best_uv[1]); /* Higher than previous candidate? */ + } + return (uv[0] > best_uv[0]); /* Further right than previous candidate? */ + } + return (dist_sq < best_dist_sq); /* Closer than previous candidate? */ +} + int BKE_image_find_nearest_tile_with_offset(const Image *image, const float co[2], float r_uv_offset[2]) { - /* Distance squared to the closest UDIM tile. */ - float dist_best_sq = FLT_MAX; - float uv_offset_best[2] = {0, 0}; + /* NOTE: If the co-ordinates are integers, take special care to break ties. */ + + zero_v2(r_uv_offset); int tile_number_best = -1; - const float co_offset[2] = {co[0] - 0.5f, co[1] - 0.5f}; + if (image->source != IMA_SRC_TILED) { + return tile_number_best; + } + + /* Distance squared to the closest UDIM tile. */ + float dist_best_sq = FLT_MAX; LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) { float uv_offset[2]; BKE_image_get_tile_uv(image, tile->tile_number, uv_offset); - /* Distance squared between co[2] and center of UDIM tile. */ - const float dist_sq = len_squared_v2v2(uv_offset, co_offset); + /* Distance squared between #co and closest point on UDIM tile. */ + const float dist_sq = distance_squared_to_udim(co, uv_offset); - if (dist_sq < dist_best_sq) { + if (dist_sq == 0) { /* Either inside in the UDIM, or on its boundary. */ + if (floorf(co[0]) == uv_offset[0] && floorf(co[1]) == uv_offset[1]) { + /* Within the half-open interval of the UDIM. */ + copy_v2_v2(r_uv_offset, uv_offset); + return tile_number_best; + } + } + + if (nearest_udim_tile_tie_break(dist_best_sq, r_uv_offset, dist_sq, uv_offset)) { + /* Tile is better than previous best, update. */ dist_best_sq = dist_sq; + copy_v2_v2(r_uv_offset, uv_offset); tile_number_best = tile->tile_number; - copy_v2_v2(uv_offset_best, uv_offset); - - if (dist_best_sq < 0.5f * 0.5f) { - break; /* No other tile can be closer. */ - } } } - if (tile_number_best != -1) { - copy_v2_v2(r_uv_offset, uv_offset_best); - } return tile_number_best; } @@ -910,7 +971,7 @@ static void image_init_color_management(Image *ima) BKE_image_user_file_path(nullptr, ima, name); - /* will set input color space to image format default's */ + /* Will set input color space to image format default's. */ ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name); if (ibuf) { @@ -1048,73 +1109,70 @@ static void image_buf_fill_isolated(void *usersata_v) } } -static ImBuf *add_ibuf_size(unsigned int width, - unsigned int height, - const char *name, - int depth, - int floatbuf, - short gen_type, - const float color[4], - ColorManagedColorspaceSettings *colorspace_settings) +static ImBuf *add_ibuf_for_tile(Image *ima, ImageTile *tile) { ImBuf *ibuf; unsigned char *rect = nullptr; float *rect_float = nullptr; float fill_color[4]; + const bool floatbuf = (tile->gen_flag & IMA_GEN_FLOAT) != 0; if (floatbuf) { - ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat); + ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_rectfloat); - if (colorspace_settings->name[0] == '\0') { + if (ima->colorspace_settings.name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get( COLOR_ROLE_DEFAULT_FLOAT); - STRNCPY(colorspace_settings->name, colorspace); + STRNCPY(ima->colorspace_settings.name, colorspace); } if (ibuf != nullptr) { rect_float = ibuf->rect_float; - IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name); + IMB_colormanagement_check_is_data(ibuf, ima->colorspace_settings.name); } - if (IMB_colormanagement_space_name_is_data(colorspace_settings->name)) { - copy_v4_v4(fill_color, color); + if (IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { + copy_v4_v4(fill_color, tile->gen_color); } else { /* The input color here should ideally be linear already, but for now * we just convert and postpone breaking the API for later. */ - srgb_to_linearrgb_v4(fill_color, color); + srgb_to_linearrgb_v4(fill_color, tile->gen_color); } } else { - ibuf = IMB_allocImBuf(width, height, depth, IB_rect); + ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_rect); - if (colorspace_settings->name[0] == '\0') { + if (ima->colorspace_settings.name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get( COLOR_ROLE_DEFAULT_BYTE); - STRNCPY(colorspace_settings->name, colorspace); + STRNCPY(ima->colorspace_settings.name, colorspace); } if (ibuf != nullptr) { rect = (unsigned char *)ibuf->rect; - IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name); + IMB_colormanagement_assign_rect_colorspace(ibuf, ima->colorspace_settings.name); } - copy_v4_v4(fill_color, color); + copy_v4_v4(fill_color, tile->gen_color); } if (!ibuf) { return nullptr; } - STRNCPY(ibuf->name, name); + STRNCPY(ibuf->name, ima->filepath); + + /* Mark the tile itself as having been generated. */ + tile->gen_flag |= IMA_GEN_TILE; ImageFillData data; - data.gen_type = gen_type; - data.width = width; - data.height = height; + data.gen_type = tile->gen_type; + data.width = tile->gen_x; + data.height = tile->gen_y; data.rect = rect; data.rect_float = rect_float; copy_v4_v4(data.fill_color, fill_color); @@ -1153,12 +1211,16 @@ Image *BKE_image_add_generated(Main *bmain, /* NOTE: leave `ima->filepath` unset, * setting it to a dummy value may write to an invalid file-path. */ - ima->gen_x = width; - ima->gen_y = height; - ima->gen_type = gen_type; - ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); - ima->gen_depth = depth; - copy_v4_v4(ima->gen_color, color); + + /* The generation info is always stored in the tiles. The first tile + * will be used for non-tiled images. */ + ImageTile *tile = static_cast<ImageTile *>(ima->tiles.first); + tile->gen_x = width; + tile->gen_y = height; + tile->gen_type = gen_type; + tile->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); + tile->gen_depth = depth; + copy_v4_v4(tile->gen_color, color); if (is_data) { STRNCPY(ima->colorspace_settings.name, @@ -1167,8 +1229,7 @@ Image *BKE_image_add_generated(Main *bmain, for (view_id = 0; view_id < 2; view_id++) { ImBuf *ibuf; - ibuf = add_ibuf_size( - width, height, ima->filepath, depth, floatbuf, gen_type, color, &ima->colorspace_settings); + ibuf = add_ibuf_for_tile(ima, tile); int index = tiled ? 0 : IMA_NO_INDEX; int entry = tiled ? 1001 : 0; image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry); @@ -2949,6 +3010,28 @@ static void image_free_tile(Image *ima, ImageTile *tile) } } +static bool image_remove_tile(Image *ima, ImageTile *tile) +{ + if (BLI_listbase_is_single(&ima->tiles)) { + /* Can't remove the last remaining tile. */ + return false; + } + + image_free_tile(ima, tile); + BLI_remlink(&ima->tiles, tile); + MEM_freeN(tile); + + return true; +} + +static void image_remove_all_tiles(Image *ima) +{ + /* Remove all but the final tile. */ + while (image_remove_tile(ima, static_cast<ImageTile *>(ima->tiles.last))) { + ; + } +} + void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) { if (ima == nullptr) { @@ -2975,11 +3058,12 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) } if (ima->source == IMA_SRC_GENERATED) { - if (ima->gen_x == 0 || ima->gen_y == 0) { + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (base_tile->gen_x == 0 || base_tile->gen_y == 0) { ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr); if (ibuf) { - ima->gen_x = ibuf->x; - ima->gen_y = ibuf->y; + base_tile->gen_x = ibuf->x; + base_tile->gen_y = ibuf->y; IMB_freeImBuf(ibuf); } } @@ -2996,16 +3080,40 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) if (ima->source != IMA_SRC_TILED) { /* Free all but the first tile. */ + image_remove_all_tiles(ima); + + /* If the remaining tile is generated, we need to again ensure that we + * wouldn't continue to use the old filepath. + * + * Otherwise, if this used to be a UDIM image, get the concrete filepath associated + * with the remaining tile and use that as the new filepath. */ ImageTile *base_tile = BKE_image_get_tile(ima, 0); - BLI_assert(base_tile == ima->tiles.first); - for (ImageTile *tile = base_tile->next, *tile_next; tile; tile = tile_next) { - tile_next = tile->next; - image_free_tile(ima, tile); - MEM_freeN(tile); + if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) { + ima->filepath[0] = '\0'; + } + else if (BKE_image_is_filename_tokenized(ima->filepath)) { + const bool was_relative = BLI_path_is_rel(ima->filepath); + + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(ima->filepath, &tile_format); + BKE_image_set_filepath_from_tile_number( + ima->filepath, udim_pattern, tile_format, base_tile->tile_number); + MEM_freeN(udim_pattern); + + if (was_relative) { + const char *relbase = ID_BLEND_PATH(bmain, &ima->id); + BLI_path_rel(ima->filepath, relbase); + } } - base_tile->next = nullptr; + + /* If the remaining tile was not number 1001, we need to reassign it so that + * ibuf lookups from the cache still succeed. */ base_tile->tile_number = 1001; - ima->tiles.last = base_tile; + } + else { + /* When changing to UDIM, attempt to tokenize the filepath. */ + char *filename = (char *)BLI_path_basename(ima->filepath); + BKE_image_ensure_tile_token(filename); } /* image buffers for non-sequence multilayer will share buffers with RenderResult, @@ -3021,6 +3129,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) image_tag_frame_recalc(ima, nullptr, iuser, ima); } BKE_image_walk_all_users(bmain, ima, image_tag_frame_recalc); + BKE_image_partial_update_mark_full_update(ima); break; @@ -3072,9 +3181,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * to account for how the two sets might or might not overlap. To be complete, we start * the refresh process by clearing all existing tiles, stopping when there's only 1 tile * left. */ - while (BKE_image_remove_tile(ima, static_cast<ImageTile *>(ima->tiles.last))) { - ; - } + image_remove_all_tiles(ima); int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; bool needs_final_cleanup = true; @@ -3257,8 +3364,7 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la } } - ImageTile *tile = MEM_cnew<ImageTile>("image new tile"); - tile->tile_number = tile_number; + ImageTile *tile = imagetile_alloc(tile_number); if (next_tile) { BLI_insertlinkbefore(&ima->tiles, next_tile, tile); @@ -3293,16 +3399,7 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return false; } - if (BLI_listbase_is_single(&ima->tiles)) { - /* Can't remove the last remaining tile. */ - return false; - } - - image_free_tile(ima, tile); - BLI_remlink(&ima->tiles, tile); - MEM_freeN(tile); - - return true; + return image_remove_tile(ima, tile); } void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_number) @@ -3364,14 +3461,7 @@ void BKE_image_sort_tiles(struct Image *ima) BLI_listbase_sort(&ima->tiles, tile_sort_cb); } -bool BKE_image_fill_tile(struct Image *ima, - ImageTile *tile, - int width, - int height, - const float color[4], - int gen_type, - int planes, - bool is_float) +bool BKE_image_fill_tile(struct Image *ima, ImageTile *tile) { if (ima == nullptr || tile == nullptr || ima->source != IMA_SRC_TILED) { return false; @@ -3379,8 +3469,7 @@ bool BKE_image_fill_tile(struct Image *ima, image_free_tile(ima, tile); - ImBuf *tile_ibuf = add_ibuf_size( - width, height, ima->filepath, planes, is_float, gen_type, color, &ima->colorspace_settings); + ImBuf *tile_ibuf = add_ibuf_for_tile(ima, tile); if (tile_ibuf != nullptr) { image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number); @@ -4553,14 +4642,22 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) } } else if (ima->source == IMA_SRC_TILED) { - if (ima->type == IMA_TYPE_IMAGE) { - /* Regular files, ibufs in flip-book, allows saving */ - ibuf = image_load_image_file(ima, iuser, entry, 0, false); + /* Nothing was cached. Check to see if the tile should be generated. */ + ImageTile *tile = BKE_image_get_tile(ima, entry); + if ((tile->gen_flag & IMA_GEN_TILE) != 0) { + ibuf = add_ibuf_for_tile(ima, tile); + image_assign_ibuf(ima, ibuf, 0, entry); } - /* no else; on load the ima type can change */ - if (ima->type == IMA_TYPE_MULTILAYER) { - /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */ - ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0); + else { + if (ima->type == IMA_TYPE_IMAGE) { + /* Regular files, ibufs in flip-book, allows saving */ + ibuf = image_load_image_file(ima, iuser, entry, 0, false); + } + /* no else; on load the ima type can change */ + if (ima->type == IMA_TYPE_MULTILAYER) { + /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */ + ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0); + } } } else if (ima->source == IMA_SRC_FILE) { @@ -4578,23 +4675,17 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) else if (ima->source == IMA_SRC_GENERATED) { /* Generated is: `ibuf` is allocated dynamically. */ /* UV test-grid or black or solid etc. */ - if (ima->gen_x == 0) { - ima->gen_x = 1024; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (base_tile->gen_x == 0) { + base_tile->gen_x = 1024; } - if (ima->gen_y == 0) { - ima->gen_y = 1024; + if (base_tile->gen_y == 0) { + base_tile->gen_y = 1024; } - if (ima->gen_depth == 0) { - ima->gen_depth = 24; + if (base_tile->gen_depth == 0) { + base_tile->gen_depth = 24; } - ibuf = add_ibuf_size(ima->gen_x, - ima->gen_y, - ima->filepath, - ima->gen_depth, - (ima->gen_flag & IMA_GEN_FLOAT) != 0, - ima->gen_type, - ima->gen_color, - &ima->colorspace_settings); + ibuf = add_ibuf_for_tile(ima, base_tile); image_assign_ibuf(ima, ibuf, index, 0); } else if (ima->source == IMA_SRC_VIEWER) { diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 9d23af39ec3..d366e9362e8 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -316,6 +316,8 @@ static void image_save_post(ReportList *reports, if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) { ima->source = IMA_SRC_FILE; ima->type = IMA_TYPE_IMAGE; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_flag &= ~IMA_GEN_TILE; } /* Update image file color space when saving to another color space. */ @@ -662,8 +664,11 @@ bool BKE_image_save( } } - /* Set the image path only if all tiles were ok. */ + /* Set the image path and clear the per-tile generated flag only if all tiles were ok. */ if (ok) { + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + tile->gen_flag &= ~IMA_GEN_TILE; + } image_save_update_filepath(ima, opts->filepath, opts); } MEM_freeN(udim_pattern); diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 3778e308db6..5a394a05d86 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -59,6 +59,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "RNA_access.h" @@ -708,6 +709,58 @@ ID *BKE_id_copy_for_duplicate(Main *bmain, return id->newid; } +static int foreach_assign_id_to_orig_callback(LibraryIDLinkCallbackData *cb_data) +{ + ID **id_p = cb_data->id_pointer; + + if (*id_p) { + ID *id = *id_p; + *id_p = DEG_get_original_id(id); + + /* If the ID changes increase the user count. + * + * This means that the reference to evaluated ID has been changed with a reference to the + * original ID which implies that the user count of the original ID is increased. + * + * The evaluated IDs do not maintain their user counter, so do not change it to avoid issues + * with the user counter going negative. */ + if (*id_p != id) { + if ((cb_data->cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(*id_p); + } + } + } + + return IDWALK_RET_NOP; +} + +ID *BKE_id_copy_for_use_in_bmain(Main *bmain, const ID *id) +{ + ID *newid = BKE_id_copy(bmain, id); + + if (newid == NULL) { + return newid; + } + + /* Assign ID references directly used by the given ID to their original complementary parts. + * + * For example, when is called on an evaluated object will assign object->data to its original + * pointer, the evaluated object->data will be kept unchanged. */ + BKE_library_foreach_ID_link(NULL, newid, foreach_assign_id_to_orig_callback, NULL, IDWALK_NOP); + + /* Shape keys reference on evaluated ID is preserved to keep driver paths available, but the key + * data is likely to be invalid now due to modifiers, so clear the shape key reference avoiding + * any possible shape corruption. */ + if (DEG_is_evaluated_id(id)) { + Key **key_p = BKE_key_from_id_p(newid); + if (key_p) { + *key_p = NULL; + } + } + + return newid; +} + /** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 3a37c29c1d0..5313cc39646 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -312,15 +312,10 @@ void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(ver { /* vert, edge and poly mapping modes never need extra cddata from source object. */ const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL); - const bool need_pnors_src = need_lnors_src || - ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL)); if (need_lnors_src) { r_cddata_mask->lmask |= CD_MASK_NORMAL; } - if (need_pnors_src) { - r_cddata_mask->pmask |= CD_MASK_NORMAL; - } } void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num) diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index dd09a3d6917..e54f2e6d687 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -16,9 +16,9 @@ template<typename T> BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh, const Span<int> looptri_indices, const Span<float3> bary_coords, - const VArray<T> &data_in, + const VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -32,30 +32,30 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh, const int v1_index = mesh.mloop[looptri.tri[1]].v; const int v2_index = mesh.mloop[looptri.tri[2]].v; - const T v0 = data_in[v0_index]; - const T v1 = data_in[v1_index]; - const T v2 = data_in[v2_index]; + const T v0 = src[v0_index]; + const T v1 = src[v1_index]; + const T v2 = src[v2_index]; const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); - data_out[i] = interpolated_value; + dst[i] = interpolated_value; } } void sample_point_attribute(const Mesh &mesh, const Span<int> looptri_indices, const Span<float3> bary_coords, - const GVArray &data_in, + const GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totvert); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totvert); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.type(); attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); sample_point_attribute<T>( - mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); + mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>()); }); } @@ -63,9 +63,9 @@ template<typename T> BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh, const Span<int> looptri_indices, const Span<float3> bary_coords, - const VArray<T> &data_in, + const VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -79,39 +79,39 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh, const int loop_index_1 = looptri.tri[1]; const int loop_index_2 = looptri.tri[2]; - const T v0 = data_in[loop_index_0]; - const T v1 = data_in[loop_index_1]; - const T v2 = data_in[loop_index_2]; + const T v0 = src[loop_index_0]; + const T v1 = src[loop_index_1]; + const T v2 = src[loop_index_2]; const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); - data_out[i] = interpolated_value; + dst[i] = interpolated_value; } } void sample_corner_attribute(const Mesh &mesh, const Span<int> looptri_indices, const Span<float3> bary_coords, - const GVArray &data_in, + const GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totloop); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totloop); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.type(); attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); sample_corner_attribute<T>( - mesh, looptri_indices, bary_coords, data_in.typed<T>(), mask, data_out.typed<T>()); + mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>()); }); } template<typename T> void sample_face_attribute(const Mesh &mesh, const Span<int> looptri_indices, - const VArray<T> &data_in, + const VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -120,23 +120,23 @@ void sample_face_attribute(const Mesh &mesh, const int looptri_index = looptri_indices[i]; const MLoopTri &looptri = looptris[looptri_index]; const int poly_index = looptri.poly; - data_out[i] = data_in[poly_index]; + dst[i] = src[poly_index]; } } void sample_face_attribute(const Mesh &mesh, const Span<int> looptri_indices, - const GVArray &data_in, + const GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totpoly); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totpoly); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.type(); attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); - sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), mask, data_out.typed<T>()); + sample_face_attribute<T>(mesh, looptri_indices, src.typed<T>(), mask, dst.typed<T>()); }); } @@ -219,45 +219,31 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src, if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { switch (mode) { case eAttributeMapMode::INTERPOLATED: - weights = ensure_barycentric_coords(); + weights = this->ensure_barycentric_coords(); break; case eAttributeMapMode::NEAREST: - weights = ensure_nearest_weights(); + weights = this->ensure_nearest_weights(); break; } } /* Interpolate the source attributes on the surface. */ switch (domain) { - case ATTR_DOMAIN_POINT: { + case ATTR_DOMAIN_POINT: sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); break; - } - case ATTR_DOMAIN_FACE: { + case ATTR_DOMAIN_FACE: sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst); break; - } - case ATTR_DOMAIN_CORNER: { + case ATTR_DOMAIN_CORNER: sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); break; - } - case ATTR_DOMAIN_EDGE: { + case ATTR_DOMAIN_EDGE: /* Not yet supported. */ break; - } - default: { + default: BLI_assert_unreachable(); break; - } - } -} - -void MeshAttributeInterpolator::sample_attribute(const GAttributeReader &src_attribute, - GSpanAttributeWriter &dst_attribute, - eAttributeMapMode mode) -{ - if (src_attribute && dst_attribute) { - this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.span); } } diff --git a/source/blender/blenkernel/intern/mesh_tessellate.cc b/source/blender/blenkernel/intern/mesh_tessellate.cc index ab0aeb88ebc..de4c60b28db 100644 --- a/source/blender/blenkernel/intern/mesh_tessellate.cc +++ b/source/blender/blenkernel/intern/mesh_tessellate.cc @@ -282,7 +282,8 @@ static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop, { struct TessellationUserTLS tls_data_dummy = {nullptr}; - struct TessellationUserData data {}; + struct TessellationUserData data { + }; data.mloop = mloop; data.mpoly = mpoly; data.mvert = mvert; diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 9b2697ecc84..5bcbdb399e4 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -1001,10 +1001,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData_MeshMasks mask = {0}; if (check_meshmask) { mask = CD_MASK_MESH; - /* Normal data isn't in the mask since it is derived data, - * but it is valid and should not be removed. */ - mask.vmask |= CD_MASK_NORMAL; - mask.pmask |= CD_MASK_NORMAL; } is_valid &= mesh_validate_customdata( diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 8ff02c7e698..1f7df2773dc 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -149,10 +149,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o cddata_masks.pmask |= CD_MASK_PROP_ALL; cddata_masks.lmask |= CD_MASK_PROP_ALL; - /* Also copy over normal layers to avoid recomputation. */ - cddata_masks.pmask |= CD_MASK_NORMAL; - cddata_masks.vmask |= CD_MASK_NORMAL; - /* Make sure Freestyle edge/face marks appear in DM for render (see T40315). * Due to Line Art implementation, edge marks should also be shown in viewport. */ #ifdef WITH_FREESTYLE diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 9b0d15ac702..b540357ce49 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1433,10 +1433,10 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->persistent_base); - MEM_SAFE_FREE(ss->preview_vert_index_list); - ss->preview_vert_index_count = 0; + MEM_SAFE_FREE(ss->preview_vert_list); + ss->preview_vert_count = 0; - MEM_SAFE_FREE(ss->preview_vert_index_list); + MEM_SAFE_FREE(ss->preview_vert_list); MEM_SAFE_FREE(ss->vertex_info.connected_component); MEM_SAFE_FREE(ss->vertex_info.boundary); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 8c1f19f0909..dae9788d21c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -555,7 +555,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, BB cb; pbvh->mesh = mesh; - pbvh->type = PBVH_FACES; + pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; pbvh->mloop = mloop; pbvh->looptri = looptri; @@ -615,7 +615,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh, { const int gridsize = key->grid_size; - pbvh->type = PBVH_GRIDS; + pbvh->header.type = PBVH_GRIDS; pbvh->grids = grids; pbvh->gridfaces = gridfaces; pbvh->grid_flag_mats = flagmats; @@ -1303,19 +1303,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, PBVH *pbvh = data->pbvh; PBVHNode *node = data->nodes[n]; - CustomData *vdata, *ldata; - - if (!pbvh->bm) { - vdata = pbvh->vdata; - ldata = pbvh->ldata; - } - else { - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; - } - if (node->flag & PBVH_RebuildDrawBuffers) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: { bool smooth = node->totprim > 0 ? pbvh->grid_flag_mats[node->prim_indices[0]].flag & ME_SMOOTH : @@ -1326,14 +1315,12 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } case PBVH_FACES: node->draw_buffers = GPU_pbvh_mesh_buffers_build( - pbvh->mpoly, - pbvh->mloop, - pbvh->looptri, + pbvh->mesh, pbvh->verts, - node->prim_indices, + pbvh->looptri, CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), - node->totprim, - pbvh->mesh); + node->prim_indices, + node->totprim); break; case PBVH_BMESH: node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags & @@ -1344,7 +1331,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, if (node->flag & PBVH_UpdateDrawBuffers) { const int update_flags = pbvh_get_buffers_update_flags(pbvh); - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: GPU_pbvh_grid_buffers_update(pbvh->vbo_id, node->draw_buffers, @@ -1360,11 +1347,12 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, update_flags); break; case PBVH_FACES: { + /* Pass vertices separately because they may be not be the same as the mesh's vertices, + * and pass normals separately because they are managed by the PBVH. */ GPU_pbvh_mesh_buffers_update(pbvh->vbo_id, node->draw_buffers, + pbvh->mesh, pbvh->verts, - vdata, - ldata, CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK), CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), pbvh->face_sets_color_seed, @@ -1376,7 +1364,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, case PBVH_BMESH: GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id, node->draw_buffers, - pbvh->bm, + pbvh->header.bm, node->bm_faces, node->bm_unique_verts, node->bm_other_verts, @@ -1405,15 +1393,15 @@ static void pbvh_check_draw_layout(PBVH *pbvh) pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; + vdata = &pbvh->header.bm->vdata; + ldata = &pbvh->header.bm->ldata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1431,7 +1419,7 @@ static void pbvh_check_draw_layout(PBVH *pbvh) * (there's no guarantee there isn't another EEVEE viewport which would * free the draw buffers and corrupt the draw cache). */ - if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) { + if (GPU_pbvh_attribute_names_update(pbvh->header.type, pbvh->vbo_id, vdata, ldata, false)) { /* attribute layout changed; force rebuild */ for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *node = pbvh->nodes + i; @@ -1451,14 +1439,14 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; + vdata = &pbvh->header.bm->vdata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1469,7 +1457,7 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, } UNUSED_VARS(vdata); - if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->header.type, PBVH_GRIDS, PBVH_BMESH)) { /* Free buffers uses OpenGL, so not in parallel. */ for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1477,11 +1465,11 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh_free_draw_buffers(pbvh, node); } else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { - if (pbvh->type == PBVH_GRIDS) { + if (pbvh->header.type == PBVH_GRIDS) { GPU_pbvh_grid_buffers_update_free( node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices); } - else if (pbvh->type == PBVH_BMESH) { + else if (pbvh->header.type == PBVH_BMESH) { GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); } } @@ -1795,15 +1783,10 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int /***************************** PBVH Access ***********************************/ -PBVHType BKE_pbvh_type(const PBVH *pbvh) -{ - return pbvh->type; -} - bool BKE_pbvh_has_faces(const PBVH *pbvh) { - if (pbvh->type == PBVH_BMESH) { - return (pbvh->bm->totface != 0); + if (pbvh->header.type == PBVH_BMESH) { + return (pbvh->header.bm->totface != 0); } return (pbvh->totprim != 0); @@ -1824,46 +1807,40 @@ void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]) BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return &pbvh->gridkey; } struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grids; } BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * pbvh->gridkey.grid_area; } int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * (pbvh->gridkey.grid_size - 1) * (pbvh->gridkey.grid_size - 1); } -BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) -{ - BLI_assert(pbvh->type == PBVH_BMESH); - return pbvh->bm; -} - /***************************** Node Access ***********************************/ void BKE_pbvh_node_mark_update(PBVHNode *node) @@ -1964,10 +1941,10 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node) return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked); } -void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, int index) +void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, PBVHVertRef vertex) { - BLI_assert(pbvh->type == PBVH_FACES); - pbvh->vert_bitmap[index] = true; + BLI_assert(pbvh->header.type == PBVH_FACES); + pbvh->vert_bitmap[vertex.i] = true; } void BKE_pbvh_node_get_loops(PBVH *pbvh, @@ -2004,7 +1981,7 @@ void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int { int tot; - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: tot = node->totprim * pbvh->gridkey.grid_area; if (r_totvert) { @@ -2042,7 +2019,7 @@ void BKE_pbvh_node_get_grids(PBVH *pbvh, int *r_gridsize, CCGElem ***r_griddata) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: if (r_grid_indices) { *r_grid_indices = node->prim_indices; @@ -2125,7 +2102,7 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, bool BKE_pbvh_node_has_vert_with_normal_update_tag(PBVH *pbvh, PBVHNode *node) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); const int *verts = node->vert_indices; const int totvert = node->uniq_verts + node->face_verts; @@ -2299,7 +2276,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_face_index, float *r_face_normal) { @@ -2339,7 +2316,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, normal_tri_v3(r_face_normal, co[0], co[1], co[2]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { @@ -2349,7 +2326,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, if (j == 0 || len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = mloop[lt->tri[j]].v; + r_active_vertex->i = mloop[lt->tri[j]].v; *r_active_face_index = lt->poly; } } @@ -2367,7 +2344,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_grid_index, float *r_face_normal) { @@ -2419,7 +2396,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); @@ -2434,8 +2411,8 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = gridkey->grid_area * grid_index + - (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); + r_active_vertex->i = gridkey->grid_area * grid_index + + (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); } } } @@ -2462,7 +2439,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal) { @@ -2472,7 +2449,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_raycast(pbvh, node, @@ -2481,7 +2458,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; @@ -2493,19 +2470,19 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; case PBVH_BMESH: - BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT); + BM_mesh_elem_index_ensure(pbvh->header.bm, BM_VERT); hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, isect_precalc, depth, use_origco, - active_vertex_index, + active_vertex, face_normal); break; } @@ -2729,7 +2706,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_nearest_to_ray( pbvh, node, origco, ray_start, ray_normal, depth, dist_sq); @@ -2820,13 +2797,13 @@ void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg) pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode); if (totnode > 0) { - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { pbvh_bmesh_normals_update(nodes, totnode); } - else if (pbvh->type == PBVH_FACES) { + else if (pbvh->header.type == PBVH_FACES) { pbvh_faces_update_normals(pbvh, nodes, totnode); } - else if (pbvh->type == PBVH_GRIDS) { + else if (pbvh->header.type == PBVH_GRIDS) { struct CCGFace **faces; int num_faces; BKE_pbvh_get_grid_updates(pbvh, true, (void ***)&faces, &num_faces); @@ -2991,7 +2968,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int /* no need for float comparison here (memory is exactly equal or not) */ if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) { copy_v3_v3(mvert->co, vertCos[a]); - BKE_pbvh_vert_tag_update_normal(pbvh, a); + BKE_pbvh_vert_tag_update_normal(pbvh, BKE_pbvh_make_vref(a)); } } @@ -3108,6 +3085,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->no = NULL; vi->fno = NULL; vi->mvert = NULL; + vi->vertex.i = 0LL; vi->respect_hide = pbvh->respect_hide; if (pbvh->respect_hide == false) { @@ -3134,10 +3112,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->vert_indices = vert_indices; vi->mverts = verts; - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts); - vi->bm_vdata = &pbvh->bm->vdata; + vi->bm_vdata = &pbvh->header.bm->vdata; vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK); } @@ -3147,7 +3125,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } vi->mask = NULL; - if (pbvh->type == PBVH_FACES) { + if (pbvh->header.type == PBVH_FACES) { vi->vert_normals = pbvh->vert_normals; vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK); @@ -3156,13 +3134,14 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m bool pbvh_has_mask(const PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->gridkey.has_mask != 0); case PBVH_FACES: return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK)); case PBVH_BMESH: - return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1)); + return (pbvh->header.bm && + (CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK) != -1)); } return false; @@ -3170,7 +3149,7 @@ bool pbvh_has_mask(const PBVH *pbvh) bool pbvh_has_face_sets(PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS)); case PBVH_FACES: @@ -3218,13 +3197,13 @@ void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, MVert *BKE_pbvh_get_verts(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->verts; } const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3] { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->vert_normals; } @@ -3242,6 +3221,7 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide) { pbvh->respect_hide = respect_hide; } + bool BKE_pbvh_is_drawing(const PBVH *pbvh) { return pbvh->is_drawing; diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index dec93826b9b..70aeb10f087 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -86,10 +86,12 @@ template<> void from_float(const float src[4], MPropCol &dst) } template<typename T> -static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4]) +static void pbvh_vertex_color_get(const PBVH &pbvh, PBVHVertRef vertex, float r_color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; int count = 0; zero_v4(r_color); @@ -99,7 +101,7 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { float temp[4]; to_float(colors[i_loop], temp); @@ -114,15 +116,17 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] } } else { - to_float(static_cast<T *>(pbvh.color_layer->data)[vertex], r_color); + to_float(static_cast<T *>(pbvh.color_layer->data)[index], r_color); } } template<typename T> -static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) +static void pbvh_vertex_color_set(PBVH &pbvh, PBVHVertRef vertex, const float color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; for (const int i_poly : Span(melem.indices, melem.count)) { const MPoly &mp = pbvh.mpoly[i_poly]; @@ -130,21 +134,21 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { from_float(color, colors[i_loop]); } } } } else { - from_float(color, static_cast<T *>(pbvh.color_layer->data)[vertex]); + from_float(color, static_cast<T *>(pbvh.color_layer->data)[index]); } } } // namespace blender::bke extern "C" { -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -152,7 +156,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) }); } -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]) +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -202,7 +206,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh, blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); for (const int i : IndexRange(indices_num)) { - blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]); + blender::bke::pbvh_vertex_color_get<T>(*pbvh, BKE_pbvh_make_vref(indices[i]), r_colors[i]); } }); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 112fd01c699..c4993684100 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -400,7 +400,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index) BM_elem_index_set(f, i); /* set_dirty! */ } /* Likely this is already dirty. */ - pbvh->bm->elem_index_dirty |= BM_FACE; + pbvh->header.bm->elem_index_dirty |= BM_FACE; pbvh_bmesh_node_split(pbvh, bbc_array, node_index); @@ -484,8 +484,8 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh, BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode); /* avoid initializing customdata because its quite involved */ - BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD); - CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data); + BMVert *v = BM_vert_create(pbvh->header.bm, co, NULL, BM_CREATE_SKIP_CD); + CustomData_bmesh_set_default(&pbvh->header.bm->vdata, &v->head.data); /* This value is logged below */ copy_v3_v3(v->no, no); @@ -512,7 +512,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(!BM_face_exists(v_tri, 3)); - BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); + BMFace *f = BM_face_create(pbvh->header.bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -1185,22 +1185,22 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, v_tri[0] = v1; v_tri[1] = v_new; v_tri[2] = v_opp; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); v_tri[0] = v_new; v_tri[1] = v2; /* v_tri[2] = v_opp; */ /* unchanged */ - e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); + e_tri[0] = BM_edge_create(pbvh->header.bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); e_tri[2] = e_tri[1]; /* switched */ - e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); + e_tri[1] = BM_edge_create(pbvh->header.bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); /* Delete original */ pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); /* Ensure new vertex is in the node */ if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) { @@ -1217,7 +1217,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, } } - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); } static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, @@ -1303,12 +1303,12 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMFace *f_adj = l_adj->f; pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); } /* Kill the edge */ BLI_assert(BM_edge_is_wire(e)); - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); /* For all remaining faces of v_del, create a new face that is the * same except it uses v_conn instead of v_del */ @@ -1355,7 +1355,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMEdge *e_tri[3]; PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f); int ni = n - pbvh->nodes; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f); /* Ensure that v_conn is in the new face's node */ @@ -1388,13 +1388,13 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, /* Remove the face */ pbvh_bmesh_face_remove(pbvh, f_del); - BM_face_kill(pbvh->bm, f_del); + BM_face_kill(pbvh->header.bm, f_del); /* Check if any of the face's edges are now unused by any * face, if so delete them */ for (int j = 0; j < 3; j++) { if (BM_edge_is_wire(e_tri[j])) { - BM_edge_kill(pbvh->bm, e_tri[j]); + BM_edge_kill(pbvh->header.bm, e_tri[j]); } } @@ -1410,7 +1410,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, v_conn = NULL; } BLI_ghash_insert(deleted_verts, v_tri[j], NULL); - BM_vert_kill(pbvh->bm, v_tri[j]); + BM_vert_kill(pbvh->header.bm, v_tri[j]); } } } @@ -1437,7 +1437,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BM_log_vert_removed(pbvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); /* v_conn == NULL is OK */ BLI_ghash_insert(deleted_verts, v_del, v_conn); - BM_vert_kill(pbvh->bm, v_del); + BM_vert_kill(pbvh->header.bm, v_del); } static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, @@ -1501,7 +1501,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *depth, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal) { bool hit = false; @@ -1538,14 +1538,14 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { if (len_squared_v3v3(location, v_tri[j]->co) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, v_tri[j]->co); - *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + r_active_vertex->i = (intptr_t)v_tri[j]; } } } @@ -1872,11 +1872,11 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, { pbvh->cd_vert_node_offset = cd_vert_node_offset; pbvh->cd_face_node_offset = cd_face_node_offset; - pbvh->bm = bm; + pbvh->header.bm = bm; BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75); - pbvh->type = PBVH_BMESH; + pbvh->header.type = PBVH_BMESH; pbvh->bm_log = log; /* TODO: choose leaf limit better */ @@ -1951,7 +1951,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2); BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); - const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK); + const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK); const int cd_vert_node_offset = pbvh->cd_vert_node_offset; const int cd_face_node_offset = pbvh->cd_face_node_offset; @@ -1967,7 +1967,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -1986,7 +1986,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -2126,13 +2126,13 @@ static void pbvh_bmesh_print(PBVH *pbvh) BMIter iter; BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f)); } fprintf(stderr, "bm_vert_to_node:\n"); BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v)); } @@ -2171,21 +2171,21 @@ static void print_flag_factors(int flag) static void pbvh_bmesh_verify(PBVH *pbvh) { /* build list of faces & verts to lookup */ - GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface); + GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totface); BMIter iter; { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE); BLI_gset_insert(faces_all, f); } } - GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert); + GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totvert); { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_insert(verts_all, v); } @@ -2207,7 +2207,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BMIter bm_iter; BMVert *v; PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, f); @@ -2240,7 +2240,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) /* Check verts */ { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { /* vertex isn't tracked */ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { continue; @@ -2286,7 +2286,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) # if 0 /* check that every vert belongs somewhere */ /* Slow */ - BM_ITER_MESH (vi, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (vi, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { bool has_unique = false; for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *n = &pbvh->nodes[i]; @@ -2299,7 +2299,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) } /* If totvert differs from number of verts inside the hash. hash-totvert is checked above. */ - BLI_assert(vert_count == pbvh->bm->totvert); + BLI_assert(vert_count == pbvh->header.bm->totvert); # endif /* Check that node elements are recorded in the top level */ diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index a4ac2744a73..0edf224e5ff 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -130,7 +130,7 @@ typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; typedef struct PBVHBMeshLog PBVHBMeshLog; struct PBVH { - PBVHType type; + struct PBVHPublic header; PBVHFlags flags; PBVHNode *nodes; @@ -183,7 +183,6 @@ struct PBVH { bool respect_hide; /* Dynamic topology */ - BMesh *bm; float bm_max_edge_len; float bm_min_edge_len; int cd_vert_node_offset; @@ -265,7 +264,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *dist, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal); bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node, const float ray_start[3], diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc index 0b5d6ad7b10..a01f5d19088 100644 --- a/source/blender/blenkernel/intern/type_conversions.cc +++ b/source/blender/blenkernel/intern/type_conversions.cc @@ -367,20 +367,38 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } +static void call_convert_to_uninitialized_fn(const GVArray &from, + const fn::MultiFunction &fn, + const IndexMask mask, + GMutableSpan to) +{ + fn::MFParamsBuilder params{fn, from.size()}; + params.add_readonly_single_input(from); + params.add_uninitialized_single_output(to); + fn::MFContextBuilder context; + fn.call_auto(mask, params, context); +} + +static void call_convert_to_uninitialized_fn(const GVArray &from, + const fn::MultiFunction &fn, + GMutableSpan to) +{ + call_convert_to_uninitialized_fn(from, fn, IndexMask(from.size()), to); +} + void DataTypeConversions::convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const { const CPPType &from_type = from_span.type(); const CPPType &to_type = to_span.type(); + BLI_assert(from_span.size() == to_span.size()); BLI_assert(this->is_convertible(from_type, to_type)); + const fn::MultiFunction *fn = this->get_conversion_multi_function( MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); - fn::MFParamsBuilder params{*fn, from_span.size()}; - params.add_readonly_single_input(from_span); + to_type.destruct_n(to_span.data(), to_span.size()); - params.add_uninitialized_single_output(to_span); - fn::MFContextBuilder context; - fn->call_auto(IndexRange(from_span.size()), params, context); + call_convert_to_uninitialized_fn(GVArray::ForSpan(from_span), *fn, to_span); } class GVArray_For_ConvertedGVArray : public GVArrayImpl { @@ -414,6 +432,20 @@ class GVArray_For_ConvertedGVArray : public GVArrayImpl { old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } + + void materialize(const IndexMask mask, void *dst) const override + { + type_->destruct_n(dst, mask.min_array_size()); + this->materialize_to_uninitialized(mask, dst); + } + + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override + { + call_convert_to_uninitialized_fn(varray_, + *old_to_new_conversions_.multi_function, + mask, + {this->type(), dst, mask.min_array_size()}); + } }; class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArrayImpl { @@ -458,6 +490,20 @@ class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArrayImpl { new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); varray_.set_by_relocate(index, buffer); } + + void materialize(const IndexMask mask, void *dst) const override + { + type_->destruct_n(dst, mask.min_array_size()); + this->materialize_to_uninitialized(mask, dst); + } + + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override + { + call_convert_to_uninitialized_fn(varray_, + *old_to_new_conversions_.multi_function, + mask, + {this->type(), dst, mask.min_array_size()}); + } }; GVArray DataTypeConversions::try_convert(GVArray varray, const CPPType &to_type) const @@ -495,9 +541,8 @@ fn::GField DataTypeConversions::try_convert(fn::GField field, const CPPType &to_ if (!this->is_convertible(from_type, to_type)) { return {}; } - const fn::MultiFunction &fn = - *bke::get_implicit_type_conversions().get_conversion_multi_function( - fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)); + const fn::MultiFunction &fn = *this->get_conversion_multi_function( + fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)); return {std::make_shared<fn::FieldOperation>(fn, Vector<fn::GField>{std::move(field)})}; } diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 0265dd037b1..88e7db1fe6c 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -456,12 +456,12 @@ WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace, WorkSpaceLayout *iter_layout; if (iter_backward) { - LISTBASE_CIRCULAR_BACKWARD_BEGIN (&workspace->layouts, iter_layout, start) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN (WorkSpaceLayout *, &workspace->layouts, iter_layout, start) { if (!callback(iter_layout, arg)) { return iter_layout; } } - LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + LISTBASE_CIRCULAR_BACKWARD_END(WorkSpaceLayout *, &workspace->layouts, iter_layout, start); } else { LISTBASE_CIRCULAR_FORWARD_BEGIN (&workspace->layouts, iter_layout, start) { diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 6fcc560d856..2b290e1ba7d 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -90,10 +90,10 @@ class IndexRange { return *this; } - constexpr Iterator operator++(int) const + constexpr Iterator operator++(int) { Iterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 237fcdae8b9..9322fa4c85b 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -320,13 +320,13 @@ struct LinkData *BLI_genericNodeN(void *data); } \ ((void)0) -#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ - if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \ +#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(type, lb, lb_iter, lb_init) \ + if ((lb)->last && (lb_init || (lb_init = (type)(lb)->last))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ +#define LISTBASE_CIRCULAR_BACKWARD_END(type, lb, lb_iter, lb_init) \ } \ - while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (lb)->last), (lb_iter != lb_init)) \ + while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (type)(lb)->last), (lb_iter != lb_init)) \ ; \ } \ ((void)0) diff --git a/source/blender/blenlib/BLI_listbase_wrapper.hh b/source/blender/blenlib/BLI_listbase_wrapper.hh index 25e029a5616..2d631cb2441 100644 --- a/source/blender/blenlib/BLI_listbase_wrapper.hh +++ b/source/blender/blenlib/BLI_listbase_wrapper.hh @@ -50,7 +50,7 @@ template<typename T> class ListBaseWrapper { Iterator operator++(int) { Iterator iterator = *this; - ++*this; + ++(*this); return iterator; } diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index 55233676ed8..95d1e344894 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -669,10 +669,10 @@ class Map { return *this; } - BaseIterator operator++(int) const + BaseIterator operator++(int) { BaseIterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index 3987c9daf0a..b8ab74d95ff 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -189,7 +189,7 @@ void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); * \endcode * * \param numerator: An integer factor in [0..denominator] (inclusive). - * \param denominator: The faction denominator (typically the number of segments of the circle). + * \param denominator: The fraction denominator (typically the number of segments of the circle). * \param r_sin: The resulting sine. * \param r_cos: The resulting cosine. */ diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index 62de4b79e41..a1b6ad9754e 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -427,10 +427,10 @@ class Set { return *this; } - Iterator operator++(int) const + Iterator operator++(int) { Iterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 438fcc4b8f7..7eab960b302 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -315,6 +315,12 @@ template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_F public: using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; + VArrayImpl_For_Span_final(const Span<T> data) + /* Cast const away, because the implementation for const and non const spans is shared. */ + : VArrayImpl_For_Span<T>({const_cast<T *>(data.data()), data.size()}) + { + } + private: CommonVArrayInfo common_info() const final { @@ -898,10 +904,7 @@ template<typename T> class VArray : public VArrayCommon<T> { VArray(varray_tag::span /* tag */, Span<T> span) { - /* Cast const away, because the virtual array implementation for const and non const spans is - * shared. */ - MutableSpan<T> mutable_span{const_cast<T *>(span.data()), span.size()}; - this->template emplace<VArrayImpl_For_Span_final<T>>(mutable_span); + this->template emplace<VArrayImpl_For_Span_final<T>>(span); } VArray(varray_tag::single /* tag */, T value, const int64_t size) diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc index 14d85b99739..31ea24eb494 100644 --- a/source/blender/blenlib/intern/string_search.cc +++ b/source/blender/blenlib/intern/string_search.cc @@ -11,8 +11,8 @@ #include "BLI_timeit.hh" /* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" -#define UI_MENU_ARROW_SEP_UNICODE 0x25b6 +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" +#define UI_MENU_ARROW_SEP_UNICODE 0x25b8 namespace blender::string_search { diff --git a/source/blender/blenlib/tests/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc index 5a97b2c7999..9dfa48b5822 100644 --- a/source/blender/blenlib/tests/BLI_set_test.cc +++ b/source/blender/blenlib/tests/BLI_set_test.cc @@ -532,8 +532,14 @@ TEST(set, ForwardIterator) Set<int>::iterator iter1 = set.begin(); int value1 = *iter1; Set<int>::iterator iter2 = iter1++; - EXPECT_EQ(*iter1, value1); - EXPECT_EQ(*iter2, *(++iter1)); + EXPECT_EQ(*iter2, value1); + EXPECT_EQ(*(++iter2), *iter1); + /* Interesting find: On GCC & MSVC this will succeed, as the 2nd argument is evaluated before the + * 1st. On Apple Clang it's the other way around, and the test fails. */ + // EXPECT_EQ(*iter1, *(++iter1)); + Set<int>::iterator iter3 = ++iter1; + /* Check that #iter1 itself changed. */ + EXPECT_EQ(*iter3, *iter1); } TEST(set, GenericAlgorithms) diff --git a/source/blender/blenlib/tests/BLI_string_search_test.cc b/source/blender/blenlib/tests/BLI_string_search_test.cc index aa6adae8d76..ab1d073ed33 100644 --- a/source/blender/blenlib/tests/BLI_string_search_test.cc +++ b/source/blender/blenlib/tests/BLI_string_search_test.cc @@ -9,7 +9,7 @@ namespace blender::string_search::tests { /* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" TEST(string_search, damerau_levenshtein_distance) { diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 5ca026ae9a3..f8bf97b17e9 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -19,6 +19,7 @@ set(INC ../windowmanager ../../../intern/clog ../../../intern/guardedalloc + ../bmesh # for writefile.c: dna_type_offsets.h ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6fad67eb217..b880f0513b8 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -359,8 +359,7 @@ static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, oldnewmap_insert_or_replace(onm, entry); } -static void oldnewmap_lib_insert( - FileData *fd, const void *oldaddr, ID *newaddr, int nr) +static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr) { oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr); } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 9ab744337a8..ff72bfe95b8 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1697,7 +1697,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /* Add subpanels for FModifiers, which requires a field to store expansion. */ + /* Add sub-panels for FModifiers, which requires a field to store expansion. */ if (!DNA_struct_elem_find(fd->filesdna, "FModifier", "short", "ui_expand_flag")) { LISTBASE_FOREACH (bAction *, act, &bmain->actions) { LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 49b14dc84a6..b98f8996a2c 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -3318,5 +3318,19 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + /* Image generation information transferred to tiles. */ + if (!DNA_struct_elem_find(fd->filesdna, "ImageTile", "int", "gen_x")) { + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + for (ImageTile *tile = ima->tiles.first; tile; tile = tile->next) { + tile->gen_x = ima->gen_x; + tile->gen_y = ima->gen_y; + tile->gen_type = ima->gen_type; + tile->gen_flag = ima->gen_flag; + tile->gen_depth = ima->gen_depth; + copy_v4_v4(tile->gen_color, ima->gen_color); + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index c2fb11fac97..113fc244086 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -66,8 +66,9 @@ static bool blo_is_builtin_template(const char *app_template) { /* For all builtin templates shipped with Blender. */ - return (!app_template || - STR_ELEM(app_template, N_("2D_Animation"), N_("Sculpting"), N_("VFX"), N_("Video_Editing"))); + return ( + !app_template || + STR_ELEM(app_template, N_("2D_Animation"), N_("Sculpting"), N_("VFX"), N_("Video_Editing"))); } static void blo_update_defaults_screen(bScreen *screen, diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index e91dab3dd6f..26f1a9e626e 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -83,7 +83,7 @@ typedef struct PathContext { /* only to access BMO flags */ BMesh *bm_bmoflag; - BMVert *v_a, *v_b; + BMVert *v_pair[2]; BLI_mempool *link_pool; } PathContext; @@ -593,17 +593,17 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } pc.bm_bmoflag = bm; - pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; - pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; + pc.v_pair[0] = ((BMVert **)op_verts_slot->data.p)[0]; + pc.v_pair[1] = ((BMVert **)op_verts_slot->data.p)[1]; /* fail! */ - if (!(pc.v_a && pc.v_b)) { + if (!(pc.v_pair[0] && pc.v_pair[1])) { return; } #ifdef DEBUG_PRINT - printf("%s: v_a: %d\n", __func__, BM_elem_index_get(pc.v_a)); - printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); + printf("%s: v_pair[0]: %d\n", __func__, BM_elem_index_get(pc.v_pair[0])); + printf("%s: v_pair[1]: %d\n", __func__, BM_elem_index_get(pc.v_pair[1])); #endif /* tag so we won't touch ever (typically hidden faces) */ @@ -618,15 +618,15 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) /* calculate matrix */ { - bm_vert_pair_to_matrix(&pc.v_a, pc.matrix); - pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co); + bm_vert_pair_to_matrix(pc.v_pair, pc.matrix); + pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_pair[0]->co); } /* add first vertex */ { PathLinkState *state; state = MEM_callocN(sizeof(*state), __func__); - state_link_add(&pc, state, (BMElem *)pc.v_a, NULL); + state_link_add(&pc, state, (BMElem *)pc.v_pair[0], NULL); BLI_heapsimple_insert(pc.states, state->dist, state); } @@ -642,7 +642,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) /* either we insert this into 'pc.states' or its freed */ bool continue_search; - if (state->link_last->ele == (BMElem *)pc.v_b) { + if (state->link_last->ele == (BMElem *)pc.v_pair[1]) { /* pass, wait until all are found */ #ifdef DEBUG_PRINT printf("%s: state %p loop found %.4f\n", __func__, state, state->dist); @@ -698,8 +698,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } while ((link = link->next)); } - BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); - BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_pair[0], VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_pair[1], VERT_OUT); BLI_mempool_destroy(pc.link_pool); diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 00efa779c4d..a8b21e4c153 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -125,13 +125,13 @@ void DEG_tag_on_visible_update(struct Main *bmain, bool do_time); const char *DEG_update_tag_as_string(IDRecalcFlag flag); /** Tag given ID for an update in all the dependency graphs. */ -void DEG_id_tag_update(struct ID *id, int flag); -void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag); +void DEG_id_tag_update(struct ID *id, unsigned int flags); +void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, unsigned int flags); void DEG_graph_id_tag_update(struct Main *bmain, struct Depsgraph *depsgraph, struct ID *id, - int flag); + unsigned int flags); /** Tag all dependency graphs when time has changed. */ void DEG_time_tag_update(struct Main *bmain); diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 763d2d29035..ac6ab5c7666 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -161,8 +161,8 @@ void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle, * This function will take care of checking which operation is required to * have transformation for the modifier, taking into account possible simulation solvers. */ -void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, - const char *description); +void DEG_add_depends_on_transform_relation(struct DepsNodeHandle *node_handle, + const char *description); /** * Adds relations from the given component of a given object to the given node diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index f36d94c7563..fc5e5189e82 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -239,13 +239,8 @@ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, { } -TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) const +TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey & /*key*/) const { - if (key.id) { - /* XXX TODO */ - return nullptr; - } - return graph_->time_source; } @@ -298,8 +293,8 @@ bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const return find_node(key) != nullptr; } -void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNodeHandle *handle, - const char *description) +void DepsgraphRelationBuilder::add_depends_on_transform_relation(const DepsNodeHandle *handle, + const char *description) { IDNode *id_node = handle->node->owner->owner; ID *id = id_node->id_orig; @@ -1977,7 +1972,6 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) void DepsgraphRelationBuilder::build_particle_systems(Object *object) { - TimeSourceKey time_src_key; OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); OperationKey eval_init_key( &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT); @@ -2263,12 +2257,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) // add geometry collider relations } /* Make sure uber update is the last in the dependencies. */ - if (object->type != OB_ARMATURE) { - /* Armatures does no longer require uber node. */ - OperationKey obdata_ubereval_key( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); - } + add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); if (object->type == OB_MBALL) { Object *mom = BKE_mball_basis_find(scene_, object); ComponentKey mom_geom_key(&mom->id, NodeType::GEOMETRY); @@ -3097,7 +3086,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) return; } - TimeSourceKey time_source_key; OperationKey copy_on_write_key(id_orig, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); /* XXX: This is a quick hack to make Alt-A to work. */ // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack"); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 7a78280f1f0..db237303027 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -85,51 +85,113 @@ struct RootPChanMap; struct TimeSourceNode; struct TimeSourceKey { - TimeSourceKey(); - TimeSourceKey(ID *id); + TimeSourceKey() = default; string identifier() const; - - ID *id; }; struct ComponentKey { - ComponentKey(); - ComponentKey(ID *id, NodeType type, const char *name = ""); + ComponentKey() = default; + + inline ComponentKey(const ID *id, NodeType type, const char *name = "") + : id(id), type(type), name(name) + { + } string identifier() const; - ID *id; - NodeType type; - const char *name; + const ID *id = nullptr; + NodeType type = NodeType::UNDEFINED; + const char *name = ""; }; struct OperationKey { - OperationKey(); - OperationKey(ID *id, NodeType component_type, const char *name, int name_tag = -1); - OperationKey( - ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag); + OperationKey() = default; + + inline OperationKey(const ID *id, NodeType component_type, const char *name, int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, + NodeType component_type, + const char *component_name, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, NodeType component_type, OperationCode opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) + { + } - OperationKey(ID *id, NodeType component_type, OperationCode opcode); - OperationKey(ID *id, NodeType component_type, const char *component_name, OperationCode opcode); + OperationKey(const ID *id, + NodeType component_type, + const char *component_name, + OperationCode opcode) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) + { + } - OperationKey( - ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag = -1); - OperationKey(ID *id, + OperationKey(const ID *id, + NodeType component_type, + OperationCode opcode, + const char *name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, NodeType component_type, const char *component_name, OperationCode opcode, const char *name, - int name_tag = -1); + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) + { + } string identifier() const; - ID *id; - NodeType component_type; - const char *component_name; - OperationCode opcode; - const char *name; - int name_tag; + const ID *id = nullptr; + NodeType component_type = NodeType::UNDEFINED; + const char *component_name = ""; + OperationCode opcode = OperationCode::OPERATION; + const char *name = ""; + int name_tag = -1; }; struct RNAPathKey { @@ -177,7 +239,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { /* Adds relation from proper transformation operation to the modifier. * Takes care of checking for possible physics solvers modifying position * of this object. */ - void add_modifier_to_transform_relation(const DepsNodeHandle *handle, const char *description); + void add_depends_on_transform_relation(const DepsNodeHandle *handle, const char *description); void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks); void add_special_eval_flag(ID *id, uint32_t flag); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index eeaab623482..8506a97c408 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -14,14 +14,6 @@ namespace blender::deg { //////////////////////////////////////////////////////////////////////////////// /* Time source. */ -TimeSourceKey::TimeSourceKey() : id(nullptr) -{ -} - -TimeSourceKey::TimeSourceKey(ID *id) : id(id) -{ -} - string TimeSourceKey::identifier() const { return string("TimeSourceKey"); @@ -30,15 +22,6 @@ string TimeSourceKey::identifier() const //////////////////////////////////////////////////////////////////////////////// // Component. -ComponentKey::ComponentKey() : id(nullptr), type(NodeType::UNDEFINED), name("") -{ -} - -ComponentKey::ComponentKey(ID *id, NodeType type, const char *name) - : id(id), type(type), name(name) -{ -} - string ComponentKey::identifier() const { const char *idname = (id) ? id->name : "<None>"; @@ -55,86 +38,6 @@ string ComponentKey::identifier() const //////////////////////////////////////////////////////////////////////////////// // Operation. -OperationKey::OperationKey() - : id(nullptr), - component_type(NodeType::UNDEFINED), - component_name(""), - opcode(OperationCode::OPERATION), - name(""), - name_tag(-1) -{ -} - -OperationKey::OperationKey(ID *id, NodeType component_type, const char *name, int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) -{ -} - -OperationKey::OperationKey( - ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) -{ -} - -OperationKey::OperationKey(ID *id, NodeType component_type, OperationCode opcode) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(""), - name_tag(-1) -{ -} - -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(""), - name_tag(-1) -{ -} - -OperationKey::OperationKey( - ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(name), - name_tag(name_tag) -{ -} - -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(name), - name_tag(name_tag) -{ -} - string OperationKey::identifier() const { string result = string("OperationKey("); diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index a207c13d646..6da290d6c4e 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -199,11 +199,11 @@ void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle, deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description); } -void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, - const char *description) +void DEG_add_depends_on_transform_relation(struct DepsNodeHandle *node_handle, + const char *description) { deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_modifier_to_transform_relation(deg_node_handle, description); + deg_node_handle->builder->add_depends_on_transform_relation(deg_node_handle, description); } void DEG_add_special_eval_flag(struct DepsNodeHandle *node_handle, ID *id, uint32_t flag) diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 9cd5980d8fe..cc742b98866 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -220,17 +220,28 @@ void depsgraph_tag_to_component_opcode(const ID *id, *component_type = NodeType::NTREE_OUTPUT; *operation_code = OperationCode::NTREE_OUTPUT; break; + + case ID_RECALC_PROVISION_26: + case ID_RECALC_PROVISION_27: + case ID_RECALC_PROVISION_28: + case ID_RECALC_PROVISION_29: + case ID_RECALC_PROVISION_30: + case ID_RECALC_PROVISION_31: + /* Silently ignore. + * The bits might be passed here from ID_RECALC_ALL. This is not a code-mistake, but just the + * way how the recalc flags are handled. */ + break; } } void id_tag_update_ntree_special( - Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) + Main *bmain, Depsgraph *graph, ID *id, unsigned int flags, eUpdateSource update_source) { bNodeTree *ntree = ntreeFromID(id); if (ntree == nullptr) { return; } - graph_id_tag_update(bmain, graph, &ntree->id, flag, update_source); + graph_id_tag_update(bmain, graph, &ntree->id, flags, update_source); } void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) @@ -407,13 +418,13 @@ string stringify_append_bit(const string &str, IDRecalcFlag tag) return result; } -string stringify_update_bitfield(int flag) +string stringify_update_bitfield(unsigned int flags) { - if (flag == 0) { + if (flags == 0) { return "LEGACY_0"; } string result; - int current_flag = flag; + unsigned int current_flag = flags; /* Special cases to avoid ALL flags form being split into * individual bits. */ if ((current_flag & ID_RECALC_PSYS_ALL) == ID_RECALC_PSYS_ALL) { @@ -421,7 +432,7 @@ string stringify_update_bitfield(int flag) } /* Handle all the rest of the flags. */ while (current_flag != 0) { - IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); + IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_uint(¤t_flag)); result = stringify_append_bit(result, tag); } return result; @@ -449,7 +460,7 @@ int deg_recalc_flags_for_legacy_zero() ID_RECALC_SOURCE | ID_RECALC_EDITORS); } -int deg_recalc_flags_effective(Depsgraph *graph, int flags) +int deg_recalc_flags_effective(Depsgraph *graph, unsigned int flags) { if (graph != nullptr) { if (!graph->is_active) { @@ -520,12 +531,12 @@ void graph_tag_ids_for_visible_update(Depsgraph *graph) * No need bother with it to tag or anything. */ continue; } - int flag = 0; + unsigned int flags = 0; if (!deg::deg_copy_on_write_is_expanded(id_node->id_cow)) { - flag |= ID_RECALC_COPY_ON_WRITE; + flags |= ID_RECALC_COPY_ON_WRITE; if (do_time) { if (BKE_animdata_from_id(id_node->id_orig) != nullptr) { - flag |= ID_RECALC_ANIMATION; + flags |= ID_RECALC_ANIMATION; } } } @@ -542,9 +553,9 @@ void graph_tag_ids_for_visible_update(Depsgraph *graph) * * TODO(sergey): Need to generalize this somehow. */ if (id_type == ID_OB) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + flags |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; } - graph_id_tag_update(bmain, graph, id_node->id_orig, flag, DEG_UPDATE_SOURCE_VISIBILITY); + graph_id_tag_update(bmain, graph, id_node->id_orig, flags, DEG_UPDATE_SOURCE_VISIBILITY); if (id_type == ID_SCE) { /* Make sure collection properties are up to date. */ id_node->tag_update(graph, DEG_UPDATE_SOURCE_VISIBILITY); @@ -614,20 +625,20 @@ NodeType geometry_tag_to_component(const ID *id) return NodeType::UNDEFINED; } -void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) +void id_tag_update(Main *bmain, ID *id, unsigned int flags, eUpdateSource update_source) { - graph_id_tag_update(bmain, nullptr, id, flag, update_source); + graph_id_tag_update(bmain, nullptr, id, flags, update_source); for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { - graph_id_tag_update(bmain, depsgraph, id, flag, update_source); + graph_id_tag_update(bmain, depsgraph, id, flags, update_source); } /* Accumulate all tags for an ID between two undo steps, so they can be * replayed for undo. */ - id->recalc_after_undo_push |= deg_recalc_flags_effective(nullptr, flag); + id->recalc_after_undo_push |= deg_recalc_flags_effective(nullptr, flags); } void graph_id_tag_update( - Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) + Main *bmain, Depsgraph *graph, ID *id, unsigned int flags, eUpdateSource update_source) { const int debug_flags = (graph != nullptr) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; if (graph != nullptr && graph->is_evaluating) { @@ -640,20 +651,20 @@ void graph_id_tag_update( printf("%s: id=%s flags=%s source=%s\n", __func__, id->name, - stringify_update_bitfield(flag).c_str(), + stringify_update_bitfield(flags).c_str(), update_source_as_string(update_source)); } IDNode *id_node = (graph != nullptr) ? graph->find_id_node(id) : nullptr; if (graph != nullptr) { DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(graph), GS(id->name)); } - if (flag == 0) { + if (flags == 0) { deg_graph_node_tag_zero(bmain, graph, id_node, update_source); } /* Store original flag in the ID. * Allows to have more granularity than a node-factory based flags. */ if (id_node != nullptr) { - id_node->id_cow->recalc |= flag; + id_node->id_cow->recalc |= flags; } /* When ID is tagged for update based on an user edits store the recalc flags in the original ID. * This way IDs in the undo steps will have this flag preserved, making it possible to restore @@ -663,20 +674,20 @@ void graph_id_tag_update( * usually newly created dependency graph skips animation update to avoid loss of unkeyed * changes). */ if (update_source == DEG_UPDATE_SOURCE_USER_EDIT) { - id->recalc |= deg_recalc_flags_effective(graph, flag); + id->recalc |= deg_recalc_flags_effective(graph, flags); } - int current_flag = flag; + unsigned int current_flag = flags; while (current_flag != 0) { - IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); + IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_uint(¤t_flag)); graph_id_tag_update_single_flag(bmain, graph, id, id_node, tag, update_source); } /* Special case for nested node tree data-blocks. */ - id_tag_update_ntree_special(bmain, graph, id, flag, update_source); + id_tag_update_ntree_special(bmain, graph, id, flags, update_source); /* Direct update tags means that something outside of simulated/cached * physics did change and that cache is to be invalidated. * This is only needed if data changes. If it's just a drawing, we keep the * point cache. */ - if (update_source == DEG_UPDATE_SOURCE_USER_EDIT && flag != ID_RECALC_SHADING) { + if (update_source == DEG_UPDATE_SOURCE_USER_EDIT && flags != ID_RECALC_SHADING) { graph_id_tag_update_single_flag( bmain, graph, id, id_node, ID_RECALC_POINT_CACHE, update_source); } @@ -741,33 +752,45 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) return "TAG_FOR_UNDO"; case ID_RECALC_NTREE_OUTPUT: return "ID_RECALC_NTREE_OUTPUT"; + + case ID_RECALC_PROVISION_26: + case ID_RECALC_PROVISION_27: + case ID_RECALC_PROVISION_28: + case ID_RECALC_PROVISION_29: + case ID_RECALC_PROVISION_30: + case ID_RECALC_PROVISION_31: + /* Silently return nullptr, indicating that there is no string representation. + * + * This is needed due to the way how logging for ID_RECALC_ALL works: it iterates over all + * bits and converts then to string. */ + return nullptr; } return nullptr; } /* Data-Based Tagging. */ -void DEG_id_tag_update(ID *id, int flag) +void DEG_id_tag_update(ID *id, unsigned int flags) { - DEG_id_tag_update_ex(G.main, id, flag); + DEG_id_tag_update_ex(G.main, id, flags); } -void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag) +void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags) { if (id == nullptr) { /* Ideally should not happen, but old depsgraph allowed this. */ return; } - deg::id_tag_update(bmain, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT); + deg::id_tag_update(bmain, id, flags, deg::DEG_UPDATE_SOURCE_USER_EDIT); } void DEG_graph_id_tag_update(struct Main *bmain, struct Depsgraph *depsgraph, struct ID *id, - int flag) + unsigned int flags) { deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph; - deg::graph_id_tag_update(bmain, graph, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT); + deg::graph_id_tag_update(bmain, graph, id, flags, deg::DEG_UPDATE_SOURCE_USER_EDIT); } void DEG_time_tag_update(struct Main *bmain) diff --git a/source/blender/depsgraph/intern/depsgraph_tag.h b/source/blender/depsgraph/intern/depsgraph_tag.h index b722aab5719..61643e6f740 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.h +++ b/source/blender/depsgraph/intern/depsgraph_tag.h @@ -18,11 +18,11 @@ struct Depsgraph; NodeType geometry_tag_to_component(const ID *id); /* Tag given ID for an update in all registered dependency graphs. */ -void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source); +void id_tag_update(Main *bmain, ID *id, unsigned int flags, eUpdateSource update_source); /* Tag given ID for an update with in a given dependency graph. */ void graph_id_tag_update( - Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source); + Main *bmain, Depsgraph *graph, ID *id, unsigned int flags, eUpdateSource update_source); /* Tag IDs of the graph for the visibility update tags. * Will do nothing if the graph is not tagged for visibility update. */ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 30352d3d19c..c34a6daa126 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -134,10 +134,12 @@ set(SRC engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c engines/eevee_next/eevee_camera.cc + engines/eevee_next/eevee_depth_of_field.cc engines/eevee_next/eevee_engine.cc engines/eevee_next/eevee_film.cc engines/eevee_next/eevee_instance.cc engines/eevee_next/eevee_material.cc + engines/eevee_next/eevee_motion_blur.cc engines/eevee_next/eevee_pipeline.cc engines/eevee_next/eevee_renderbuffers.cc engines/eevee_next/eevee_sampling.cc @@ -361,6 +363,22 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_attributes_lib.glsl engines/eevee_next/shaders/eevee_camera_lib.glsl + engines/eevee_next/shaders/eevee_colorspace_lib.glsl + engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl + engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_gather_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_hole_fill_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_lib.glsl + engines/eevee_next/shaders/eevee_depth_of_field_reduce_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_resolve_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_scatter_frag.glsl + engines/eevee_next/shaders/eevee_depth_of_field_scatter_vert.glsl + engines/eevee_next/shaders/eevee_depth_of_field_setup_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_stabilize_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_tiles_dilate_comp.glsl + engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl engines/eevee_next/shaders/eevee_film_comp.glsl engines/eevee_next/shaders/eevee_film_frag.glsl engines/eevee_next/shaders/eevee_film_lib.glsl @@ -368,7 +386,12 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl engines/eevee_next/shaders/eevee_geom_world_vert.glsl + engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_lib.glsl engines/eevee_next/shaders/eevee_nodetree_lib.glsl + engines/eevee_next/shaders/eevee_sampling_lib.glsl engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl engines/eevee_next/shaders/eevee_surf_depth_frag.glsl engines/eevee_next/shaders/eevee_surf_forward_frag.glsl diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_frag.glsl index 06dcbeaed66..7230758a93f 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_frag.glsl @@ -67,7 +67,7 @@ void main(void) /* Occlude the sprite with geometry from the same field * using a VSM like chebychev test (slide 85). */ float mean = occlusion_data.x; - float variance = occlusion_data.x; + float variance = occlusion_data.y; shapes *= variance * safe_rcp(variance + sqr(max(cocs * correction_fac - mean, 0.0))); } diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh index 8bf64199246..49f9b14e11b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_camera.hh +++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh @@ -82,7 +82,6 @@ class Camera { private: Instance &inst_; - /** Double buffered to detect changes and have history for re-projection. */ CameraDataBuf data_; public: @@ -112,6 +111,10 @@ class Camera { { return data_.type == CAMERA_ORTHO; } + bool is_perspective() const + { + return data_.type == CAMERA_PERSP; + } const float3 &position() const { return *reinterpret_cast<const float3 *>(data_.viewinv[3]); diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 1e7979b594e..c1e901845f1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -44,4 +44,24 @@ /* Minimum visibility size. */ #define LIGHTPROBE_FILTER_VIS_GROUP_SIZE 16 +/* Film. */ #define FILM_GROUP_SIZE 16 + +/* Motion Blur. */ +#define MOTION_BLUR_GROUP_SIZE 32 +#define MOTION_BLUR_DILATE_GROUP_SIZE 512 + +/* Depth Of Field. */ +#define DOF_TILES_SIZE 8 +#define DOF_TILES_FLATTEN_GROUP_SIZE DOF_TILES_SIZE +#define DOF_TILES_DILATE_GROUP_SIZE 8 +#define DOF_BOKEH_LUT_SIZE 32 +#define DOF_MAX_SLIGHT_FOCUS_RADIUS 5 +#define DOF_SLIGHT_FOCUS_SAMPLE_MAX 16 +#define DOF_MIP_COUNT 4 +#define DOF_REDUCE_GROUP_SIZE (1 << (DOF_MIP_COUNT - 1)) +#define DOF_DEFAULT_GROUP_SIZE 32 +#define DOF_STABILIZE_GROUP_SIZE 16 +#define DOF_FILTER_GROUP_SIZE 8 +#define DOF_GATHER_GROUP_SIZE DOF_TILES_SIZE +#define DOF_RESOLVE_GROUP_SIZE (DOF_TILES_SIZE * 2) diff --git a/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc new file mode 100644 index 00000000000..3700076153e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.cc @@ -0,0 +1,768 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * Depth of field post process effect. + * + * There are 2 methods to achieve this effect. + * - The first uses projection matrix offsetting and sample accumulation to give + * reference quality depth of field. But this needs many samples to hide the + * under-sampling. + * - The second one is a post-processing based one. It follows the + * implementation described in the presentation + * "Life of a Bokeh - Siggraph 2018" from Guillaume Abadie. + * There are some difference with our actual implementation that prioritize quality. + */ + +#include "DRW_render.h" + +#include "BKE_camera.h" +#include "DNA_camera_types.h" + +#include "GPU_platform.h" +#include "GPU_texture.h" +#include "GPU_uniform_buffer.h" + +#include "eevee_camera.hh" +#include "eevee_instance.hh" +#include "eevee_sampling.hh" +#include "eevee_shader.hh" +#include "eevee_shader_shared.hh" + +#include "eevee_depth_of_field.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name Depth of field + * \{ */ + +void DepthOfField::init() +{ + const SceneEEVEE &sce_eevee = inst_.scene->eevee; + const Object *camera_object_eval = inst_.camera_eval_object; + const ::Camera *camera = (camera_object_eval) ? + reinterpret_cast<const ::Camera *>(camera_object_eval->data) : + nullptr; + if (camera == nullptr) { + /* Set to invalid value for update detection */ + data_.scatter_color_threshold = -1.0f; + return; + } + /* Reminder: These are parameters not interpolated by motion blur. */ + int update = 0; + int sce_flag = sce_eevee.flag; + update += assign_if_different(do_jitter_, (sce_flag & SCE_EEVEE_DOF_JITTER) != 0); + update += assign_if_different(user_overblur_, sce_eevee.bokeh_overblur / 100.0f); + update += assign_if_different(fx_max_coc_, sce_eevee.bokeh_max_size); + update += assign_if_different(data_.scatter_color_threshold, sce_eevee.bokeh_threshold); + update += assign_if_different(data_.scatter_neighbor_max_color, sce_eevee.bokeh_neighbor_max); + update += assign_if_different(data_.bokeh_blades, float(camera->dof.aperture_blades)); + if (update > 0) { + inst_.sampling.reset(); + } +} + +void DepthOfField::sync() +{ + const Camera &camera = inst_.camera; + const Object *camera_object_eval = inst_.camera_eval_object; + const ::Camera *camera_data = (camera_object_eval) ? + reinterpret_cast<const ::Camera *>(camera_object_eval->data) : + nullptr; + + int update = 0; + + if (camera_data == nullptr || (camera_data->dof.flag & CAM_DOF_ENABLED) == 0) { + update += assign_if_different(jitter_radius_, 0.0f); + update += assign_if_different(fx_radius_, 0.0f); + if (update > 0) { + inst_.sampling.reset(); + } + return; + } + + float2 anisotropic_scale = {clamp_f(1.0f / camera_data->dof.aperture_ratio, 1e-5f, 1.0f), + clamp_f(camera_data->dof.aperture_ratio, 1e-5f, 1.0f)}; + update += assign_if_different(data_.bokeh_anisotropic_scale, anisotropic_scale); + update += assign_if_different(data_.bokeh_rotation, camera_data->dof.aperture_rotation); + update += assign_if_different(focus_distance_, + BKE_camera_object_dof_distance(camera_object_eval)); + data_.bokeh_anisotropic_scale_inv = 1.0f / data_.bokeh_anisotropic_scale; + + float fstop = max_ff(camera_data->dof.aperture_fstop, 1e-5f); + + if (update) { + inst_.sampling.reset(); + } + + float aperture = 1.0f / (2.0f * fstop); + if (camera.is_perspective()) { + aperture *= camera_data->lens * 1e-3f; + } + + if (camera.is_orthographic()) { + /* FIXME: Why is this needed? Some kind of implicit unit conversion? */ + aperture *= 0.04f; + /* Really strange behavior from Cycles but replicating. */ + focus_distance_ += camera.data_get().clip_near; + } + + if (camera.is_panoramic()) { + /* FIXME: Eyeballed. */ + aperture *= 0.185f; + } + + if (camera_data->dof.aperture_ratio < 1.0) { + /* If ratio is scaling the bokeh outwards, we scale the aperture so that + * the gather kernel size will encompass the maximum axis. */ + aperture /= max_ff(camera_data->dof.aperture_ratio, 1e-5f); + } + + float jitter_radius, fx_radius; + + /* Balance blur radius between fx dof and jitter dof. */ + if (do_jitter_ && (inst_.sampling.dof_ring_count_get() > 0) && !camera.is_panoramic() && + !inst_.is_viewport()) { + /* Compute a minimal overblur radius to fill the gaps between the samples. + * This is just the simplified form of dividing the area of the bokeh by + * the number of samples. */ + float minimal_overblur = 1.0f / sqrtf(inst_.sampling.dof_sample_count_get()); + + fx_radius = (minimal_overblur + user_overblur_) * aperture; + /* Avoid dilating the shape. Over-blur only soften. */ + jitter_radius = max_ff(0.0f, aperture - fx_radius); + } + else { + jitter_radius = 0.0f; + fx_radius = aperture; + } + + /* Disable post fx if result wouldn't be noticeable. */ + if (fx_max_coc_ <= 0.5f) { + fx_radius = 0.0f; + } + + update += assign_if_different(jitter_radius_, jitter_radius); + update += assign_if_different(fx_radius_, fx_radius); + if (update > 0) { + inst_.sampling.reset(); + } + + if (fx_radius_ == 0.0f) { + return; + } + + /* TODO(fclem): Once we render into multiple view, we will need to use the maximum resolution. */ + int2 max_render_res = inst_.film.render_extent_get(); + int2 half_res = math::divide_ceil(max_render_res, int2(2)); + int2 reduce_size = math::ceil_to_multiple(half_res, int2(DOF_REDUCE_GROUP_SIZE)); + + data_.gather_uv_fac = 1.0f / float2(reduce_size); + + /* Now that we know the maximum render resolution of every view, using depth of field, allocate + * the reduced buffers. Color needs to be signed format here. See note in shader for + * explanation. Do not use texture pool because of needs mipmaps. */ + reduced_color_tx_.ensure_2d(GPU_RGBA16F, reduce_size, nullptr, DOF_MIP_COUNT); + reduced_coc_tx_.ensure_2d(GPU_R16F, reduce_size, nullptr, DOF_MIP_COUNT); + reduced_color_tx_.ensure_mip_views(); + reduced_coc_tx_.ensure_mip_views(); + + /* Resize the scatter list to contain enough entry to cover half the screen with sprites (which + * is unlikely due to local contrast test). */ + data_.scatter_max_rect = (reduced_color_tx_.pixel_count() / 4) / 2; + scatter_fg_list_buf_.resize(data_.scatter_max_rect); + scatter_bg_list_buf_.resize(data_.scatter_max_rect); + + bokeh_lut_pass_sync(); + setup_pass_sync(); + stabilize_pass_sync(); + downsample_pass_sync(); + reduce_pass_sync(); + tiles_flatten_pass_sync(); + tiles_dilate_pass_sync(); + gather_pass_sync(); + filter_pass_sync(); + scatter_pass_sync(); + hole_fill_pass_sync(); + resolve_pass_sync(); +} + +void DepthOfField::jitter_apply(float4x4 &winmat, float4x4 &viewmat) +{ + if (jitter_radius_ == 0.0f) { + return; + } + + float radius, theta; + inst_.sampling.dof_disk_sample_get(&radius, &theta); + + if (data_.bokeh_blades >= 3.0f) { + theta = circle_to_polygon_angle(data_.bokeh_blades, theta); + radius *= circle_to_polygon_radius(data_.bokeh_blades, theta); + } + radius *= jitter_radius_; + theta += data_.bokeh_rotation; + + /* Sample in View Space. */ + float2 sample = float2(radius * cosf(theta), radius * sinf(theta)); + sample *= data_.bokeh_anisotropic_scale; + /* Convert to NDC Space. */ + float3 jitter = float3(UNPACK2(sample), -focus_distance_); + float3 center = float3(0.0f, 0.0f, -focus_distance_); + mul_project_m4_v3(winmat.ptr(), jitter); + mul_project_m4_v3(winmat.ptr(), center); + + const bool is_ortho = (winmat[2][3] != -1.0f); + if (is_ortho) { + sample *= focus_distance_; + } + /* Translate origin. */ + sub_v2_v2(viewmat[3], sample); + /* Skew winmat Z axis. */ + add_v2_v2(winmat[2], center - jitter); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Passes setup. + * \{ */ + +void DepthOfField::bokeh_lut_pass_sync() +{ + const bool has_anisotropy = data_.bokeh_anisotropic_scale != float2(1.0f); + if (!has_anisotropy && (data_.bokeh_blades == 0.0)) { + /* No need for LUTs in these cases. */ + bokeh_lut_ps_ = nullptr; + return; + } + + /* Precompute bokeh texture. */ + bokeh_lut_ps_ = DRW_pass_create("Dof.bokeh_lut_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_BOKEH_LUT); + DRWShadingGroup *grp = DRW_shgroup_create(sh, bokeh_lut_ps_); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_image_ref(grp, "out_gather_lut_img", &bokeh_gather_lut_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_scatter_lut_img", &bokeh_scatter_lut_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_resolve_lut_img", &bokeh_resolve_lut_tx_); + DRW_shgroup_call_compute(grp, 1, 1, 1); +} + +void DepthOfField::setup_pass_sync() +{ + RenderBuffers &render_buffers = inst_.render_buffers; + + setup_ps_ = DRW_pass_create("Dof.setup_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_SETUP); + DRWShadingGroup *grp = DRW_shgroup_create(sh, setup_ps_); + DRW_shgroup_uniform_texture_ref_ex(grp, "color_tx", &input_color_tx_, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &setup_color_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_coc_img", &setup_coc_tx_); + DRW_shgroup_call_compute_ref(grp, dispatch_setup_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); +} + +void DepthOfField::stabilize_pass_sync() +{ + RenderBuffers &render_buffers = inst_.render_buffers; + VelocityModule &velocity = inst_.velocity; + + stabilize_ps_ = DRW_pass_create("Dof.stabilize_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_STABILIZE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, stabilize_ps_); + DRW_shgroup_uniform_block_ref(grp, "camera_prev", &(*velocity.camera_steps[STEP_PREVIOUS])); + DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*velocity.camera_steps[STEP_CURRENT])); + /* This is only for temporal stability. The next step is not needed. */ + DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*velocity.camera_steps[STEP_PREVIOUS])); + DRW_shgroup_uniform_texture_ref_ex(grp, "coc_tx", &setup_coc_tx_, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "color_tx", &setup_color_tx_, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocity_tx", &render_buffers.vector_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "in_history_tx", &stabilize_input_, with_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter); + DRW_shgroup_uniform_bool(grp, "use_history", &stabilize_valid_history_, 1); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_image(grp, "out_coc_img", reduced_coc_tx_.mip_view(0)); + DRW_shgroup_uniform_image(grp, "out_color_img", reduced_color_tx_.mip_view(0)); + DRW_shgroup_uniform_image_ref(grp, "out_history_img", &stabilize_output_tx_); + DRW_shgroup_call_compute_ref(grp, dispatch_stabilize_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); +} + +void DepthOfField::downsample_pass_sync() +{ + downsample_ps_ = DRW_pass_create("Dof.downsample_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_DOWNSAMPLE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, downsample_ps_); + DRW_shgroup_uniform_texture_ex(grp, "color_tx", reduced_color_tx_.mip_view(0), no_filter); + DRW_shgroup_uniform_texture_ex(grp, "coc_tx", reduced_coc_tx_.mip_view(0), no_filter); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &downsample_tx_); + DRW_shgroup_call_compute_ref(grp, dispatch_downsample_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); +} + +void DepthOfField::reduce_pass_sync() +{ + reduce_ps_ = DRW_pass_create("Dof.reduce_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_REDUCE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, reduce_ps_); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_texture_ref_ex(grp, "downsample_tx", &downsample_tx_, no_filter); + DRW_shgroup_storage_block(grp, "scatter_fg_list_buf", scatter_fg_list_buf_); + DRW_shgroup_storage_block(grp, "scatter_bg_list_buf", scatter_bg_list_buf_); + DRW_shgroup_storage_block(grp, "scatter_fg_indirect_buf", scatter_fg_indirect_buf_); + DRW_shgroup_storage_block(grp, "scatter_bg_indirect_buf", scatter_bg_indirect_buf_); + DRW_shgroup_uniform_image(grp, "inout_color_lod0_img", reduced_color_tx_.mip_view(0)); + DRW_shgroup_uniform_image(grp, "out_color_lod1_img", reduced_color_tx_.mip_view(1)); + DRW_shgroup_uniform_image(grp, "out_color_lod2_img", reduced_color_tx_.mip_view(2)); + DRW_shgroup_uniform_image(grp, "out_color_lod3_img", reduced_color_tx_.mip_view(3)); + DRW_shgroup_uniform_image(grp, "in_coc_lod0_img", reduced_coc_tx_.mip_view(0)); + DRW_shgroup_uniform_image(grp, "out_coc_lod1_img", reduced_coc_tx_.mip_view(1)); + DRW_shgroup_uniform_image(grp, "out_coc_lod2_img", reduced_coc_tx_.mip_view(2)); + DRW_shgroup_uniform_image(grp, "out_coc_lod3_img", reduced_coc_tx_.mip_view(3)); + DRW_shgroup_call_compute_ref(grp, dispatch_reduce_size_); + /* NOTE: Command buffer barrier is done automatically by the GPU backend. */ + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_STORAGE); +} + +void DepthOfField::tiles_flatten_pass_sync() +{ + tiles_flatten_ps_ = DRW_pass_create("Dof.tiles_flatten_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_TILES_FLATTEN); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_flatten_ps_); + /* NOTE(fclem): We should use the reduced_coc_tx_ as it is stable, but we need the slight focus + * flag from the setup pass. A better way would be to do the brute-force in focus gather without + * this. */ + DRW_shgroup_uniform_texture_ref_ex(grp, "coc_tx", &setup_coc_tx_, no_filter); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_fg_img", &tiles_fg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_bg_img", &tiles_bg_tx_.current()); + DRW_shgroup_call_compute_ref(grp, dispatch_tiles_flatten_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS); +} + +void DepthOfField::tiles_dilate_pass_sync() +{ + tiles_dilate_minmax_ps_ = DRW_pass_create("Dof.tiles_dilate_minmax_ps_", DRW_STATE_NO_DRAW); + tiles_dilate_minabs_ps_ = DRW_pass_create("Dof.tiles_dilate_minabs_ps_", DRW_STATE_NO_DRAW); + for (int pass = 0; pass < 2; pass++) { + DRWPass *drw_pass = (pass == 0) ? tiles_dilate_minmax_ps_ : tiles_dilate_minabs_ps_; + GPUShader *sh = inst_.shaders.static_shader_get((pass == 0) ? DOF_TILES_DILATE_MINMAX : + DOF_TILES_DILATE_MINABS); + DRWShadingGroup *grp = DRW_shgroup_create(sh, drw_pass); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_fg_img", &tiles_fg_tx_.previous()); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_bg_img", &tiles_bg_tx_.previous()); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_fg_img", &tiles_fg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_bg_img", &tiles_bg_tx_.current()); + DRW_shgroup_uniform_int(grp, "ring_count", &tiles_dilate_ring_count_, 1); + DRW_shgroup_uniform_int(grp, "ring_width_multiplier", &tiles_dilate_ring_width_mul_, 1); + DRW_shgroup_call_compute_ref(grp, dispatch_tiles_dilate_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS); + } +} + +void DepthOfField::gather_pass_sync() +{ + gather_fg_ps_ = DRW_pass_create("Dof.gather_fg_ps_", DRW_STATE_NO_DRAW); + gather_bg_ps_ = DRW_pass_create("Dof.gather_bg_ps_", DRW_STATE_NO_DRAW); + for (int pass = 0; pass < 2; pass++) { + SwapChain<TextureFromPool, 2> &color_chain = (pass == 0) ? color_fg_tx_ : color_bg_tx_; + SwapChain<TextureFromPool, 2> &weight_chain = (pass == 0) ? weight_fg_tx_ : weight_bg_tx_; + bool use_lut = bokeh_lut_ps_ != nullptr; + eShaderType sh_type = (pass == 0) ? + (use_lut ? DOF_GATHER_FOREGROUND_LUT : DOF_GATHER_FOREGROUND) : + (use_lut ? DOF_GATHER_BACKGROUND_LUT : DOF_GATHER_BACKGROUND); + GPUShader *sh = inst_.shaders.static_shader_get(sh_type); + DRWShadingGroup *grp = DRW_shgroup_create(sh, (pass == 0) ? gather_fg_ps_ : gather_bg_ps_); + inst_.sampling.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_texture_ex(grp, "color_bilinear_tx", reduced_color_tx_, gather_bilinear); + DRW_shgroup_uniform_texture_ex(grp, "color_tx", reduced_color_tx_, gather_nearest); + DRW_shgroup_uniform_texture_ex(grp, "coc_tx", reduced_coc_tx_, gather_nearest); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_fg_img", &tiles_fg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_bg_img", &tiles_bg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &color_chain.current()); + DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &weight_chain.current()); + DRW_shgroup_uniform_image_ref(grp, "out_occlusion_img", &occlusion_tx_); + DRW_shgroup_uniform_texture_ref(grp, "bokeh_lut_tx", &bokeh_gather_lut_tx_); + DRW_shgroup_call_compute_ref(grp, dispatch_gather_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + } +} + +void DepthOfField::filter_pass_sync() +{ + filter_fg_ps_ = DRW_pass_create("Dof.filter_fg_ps_", DRW_STATE_NO_DRAW); + filter_bg_ps_ = DRW_pass_create("Dof.filter_bg_ps_", DRW_STATE_NO_DRAW); + for (int pass = 0; pass < 2; pass++) { + SwapChain<TextureFromPool, 2> &color_chain = (pass == 0) ? color_fg_tx_ : color_bg_tx_; + SwapChain<TextureFromPool, 2> &weight_chain = (pass == 0) ? weight_fg_tx_ : weight_bg_tx_; + GPUShader *sh = inst_.shaders.static_shader_get(DOF_FILTER); + DRWShadingGroup *grp = DRW_shgroup_create(sh, (pass == 0) ? filter_fg_ps_ : filter_bg_ps_); + DRW_shgroup_uniform_texture_ref(grp, "color_tx", &color_chain.previous()); + DRW_shgroup_uniform_texture_ref(grp, "weight_tx", &weight_chain.previous()); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &color_chain.current()); + DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &weight_chain.current()); + DRW_shgroup_call_compute_ref(grp, dispatch_filter_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + } +} + +void DepthOfField::scatter_pass_sync() +{ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL; + scatter_fg_ps_ = DRW_pass_create("Dof.scatter_fg_ps_", state); + scatter_bg_ps_ = DRW_pass_create("Dof.scatter_bg_ps_", state); + for (int pass = 0; pass < 2; pass++) { + GPUStorageBuf *scatter_buf = (pass == 0) ? scatter_fg_indirect_buf_ : scatter_bg_indirect_buf_; + GPUStorageBuf *rect_list_buf = (pass == 0) ? scatter_fg_list_buf_ : scatter_bg_list_buf_; + + GPUShader *sh = inst_.shaders.static_shader_get(DOF_SCATTER); + DRWShadingGroup *grp = DRW_shgroup_create(sh, (pass == 0) ? scatter_fg_ps_ : scatter_bg_ps_); + DRW_shgroup_uniform_bool_copy(grp, "use_bokeh_lut", bokeh_lut_ps_ != nullptr); + DRW_shgroup_storage_block(grp, "scatter_list_buf", rect_list_buf); + DRW_shgroup_uniform_texture_ref(grp, "bokeh_lut_tx", &bokeh_scatter_lut_tx_); + DRW_shgroup_uniform_texture_ref(grp, "occlusion_tx", &occlusion_tx_); + DRW_shgroup_call_procedural_indirect(grp, GPU_PRIM_TRI_STRIP, nullptr, scatter_buf); + if (pass == 0) { + /* Avoid background gather pass writing to the occlusion_tx mid pass. */ + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS); + } + } +} + +void DepthOfField::hole_fill_pass_sync() +{ + hole_fill_ps_ = DRW_pass_create("Dof.hole_fill_ps_", DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(DOF_GATHER_HOLE_FILL); + DRWShadingGroup *grp = DRW_shgroup_create(sh, hole_fill_ps_); + inst_.sampling.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_texture_ex(grp, "color_bilinear_tx", reduced_color_tx_, gather_bilinear); + DRW_shgroup_uniform_texture_ex(grp, "color_tx", reduced_color_tx_, gather_nearest); + DRW_shgroup_uniform_texture_ex(grp, "coc_tx", reduced_coc_tx_, gather_nearest); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_fg_img", &tiles_fg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_bg_img", &tiles_bg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &hole_fill_color_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &hole_fill_weight_tx_); + DRW_shgroup_call_compute_ref(grp, dispatch_gather_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); +} + +void DepthOfField::resolve_pass_sync() +{ + eGPUSamplerState with_filter = GPU_SAMPLER_FILTER; + RenderBuffers &render_buffers = inst_.render_buffers; + + resolve_ps_ = DRW_pass_create("Dof.resolve_ps_", DRW_STATE_NO_DRAW); + bool use_lut = bokeh_lut_ps_ != nullptr; + eShaderType sh_type = use_lut ? DOF_RESOLVE_LUT : DOF_RESOLVE; + GPUShader *sh = inst_.shaders.static_shader_get(sh_type); + DRWShadingGroup *grp = DRW_shgroup_create(sh, resolve_ps_); + inst_.sampling.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "dof_buf", data_); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "color_tx", &input_color_tx_, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "stable_color_tx", &resolve_stable_color_tx_, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "color_bg_tx", &color_bg_tx_.current(), with_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "color_fg_tx", &color_fg_tx_.current(), with_filter); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_fg_img", &tiles_fg_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_bg_img", &tiles_bg_tx_.current()); + DRW_shgroup_uniform_texture_ref(grp, "weight_bg_tx", &weight_bg_tx_.current()); + DRW_shgroup_uniform_texture_ref(grp, "weight_fg_tx", &weight_fg_tx_.current()); + DRW_shgroup_uniform_texture_ref(grp, "color_hole_fill_tx", &hole_fill_color_tx_); + DRW_shgroup_uniform_texture_ref(grp, "weight_hole_fill_tx", &hole_fill_weight_tx_); + DRW_shgroup_uniform_texture_ref(grp, "bokeh_lut_tx", &bokeh_resolve_lut_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &output_color_tx_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + DRW_shgroup_call_compute_ref(grp, dispatch_resolve_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Post-FX Rendering. + * \{ */ + +/* Similar to Film::update_sample_table() but with constant filter radius and constant sample + * count. */ +void DepthOfField::update_sample_table() +{ + float2 subpixel_offset = inst_.film.pixel_jitter_get(); + /* Since the film jitter is in full-screen res, divide by 2 to get the jitter in half res. */ + subpixel_offset *= 0.5; + + /* Same offsets as in dof_spatial_filtering(). */ + const std::array<int2, 4> plus_offsets = {int2(-1, 0), int2(0, -1), int2(1, 0), int2(0, 1)}; + + const float radius = 1.5f; + int i = 0; + for (int2 offset : plus_offsets) { + float2 pixel_ofs = float2(offset) - subpixel_offset; + data_.filter_samples_weight[i++] = film_filter_weight(radius, math::length_squared(pixel_ofs)); + } + data_.filter_center_weight = film_filter_weight(radius, math::length_squared(subpixel_offset)); +} + +void DepthOfField::render(GPUTexture **input_tx, + GPUTexture **output_tx, + DepthOfFieldBuffer &dof_buffer) +{ + if (fx_radius_ == 0.0f) { + return; + } + + input_color_tx_ = *input_tx; + output_color_tx_ = *output_tx; + extent_ = {GPU_texture_width(input_color_tx_), GPU_texture_height(input_color_tx_)}; + + { + const CameraData &cam_data = inst_.camera.data_get(); + data_.camera_type = cam_data.type; + /* OPTI(fclem) Could be optimized. */ + float3 jitter = float3(fx_radius_, 0.0f, -focus_distance_); + float3 center = float3(0.0f, 0.0f, -focus_distance_); + mul_project_m4_v3(cam_data.winmat.ptr(), jitter); + mul_project_m4_v3(cam_data.winmat.ptr(), center); + /* Simplify CoC calculation to a simple MADD. */ + if (inst_.camera.is_orthographic()) { + data_.coc_mul = (center[0] - jitter[0]) * 0.5f * extent_[0]; + data_.coc_bias = focus_distance_ * data_.coc_mul; + } + else { + data_.coc_bias = -(center[0] - jitter[0]) * 0.5f * extent_[0]; + data_.coc_mul = focus_distance_ * data_.coc_bias; + } + + float min_fg_coc = coc_radius_from_camera_depth(data_, -cam_data.clip_near); + float max_bg_coc = coc_radius_from_camera_depth(data_, -cam_data.clip_far); + if (data_.camera_type != CAMERA_ORTHO) { + /* Background is at infinity so maximum CoC is the limit of coc_radius_from_camera_depth + * at -inf. We only do this for perspective camera since orthographic coc limit is inf. */ + max_bg_coc = data_.coc_bias; + } + /* Clamp with user defined max. */ + data_.coc_abs_max = min_ff(max_ff(fabsf(min_fg_coc), fabsf(max_bg_coc)), fx_max_coc_); + /* TODO(fclem): Make this dependent of the quality of the gather pass. */ + data_.scatter_coc_threshold = 4.0f; + + update_sample_table(); + + data_.push_update(); + } + + int2 half_res = math::divide_ceil(extent_, int2(2)); + int2 quarter_res = math::divide_ceil(extent_, int2(4)); + int2 tile_res = math::divide_ceil(half_res, int2(DOF_TILES_SIZE)); + + dispatch_setup_size_ = int3(math::divide_ceil(half_res, int2(DOF_DEFAULT_GROUP_SIZE)), 1); + dispatch_stabilize_size_ = int3(math::divide_ceil(half_res, int2(DOF_STABILIZE_GROUP_SIZE)), 1); + dispatch_downsample_size_ = int3(math::divide_ceil(quarter_res, int2(DOF_DEFAULT_GROUP_SIZE)), + 1); + dispatch_reduce_size_ = int3(math::divide_ceil(half_res, int2(DOF_REDUCE_GROUP_SIZE)), 1); + dispatch_tiles_flatten_size_ = int3(math::divide_ceil(half_res, int2(DOF_TILES_SIZE)), 1); + dispatch_tiles_dilate_size_ = int3( + math::divide_ceil(tile_res, int2(DOF_TILES_DILATE_GROUP_SIZE)), 1); + dispatch_gather_size_ = int3(math::divide_ceil(half_res, int2(DOF_GATHER_GROUP_SIZE)), 1); + dispatch_filter_size_ = int3(math::divide_ceil(half_res, int2(DOF_FILTER_GROUP_SIZE)), 1); + dispatch_resolve_size_ = int3(math::divide_ceil(extent_, int2(DOF_RESOLVE_GROUP_SIZE)), 1); + + if (GPU_type_matches_ex(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL)) { + /* On Mesa, there is a sync bug which can make a portion of the main pass (usually one shader) + * leave blocks of un-initialized memory. Doing a flush seems to alleviate the issue. */ + GPU_flush(); + } + + DRW_stats_group_start("Depth of Field"); + + { + DRW_stats_group_start("Setup"); + { + bokeh_gather_lut_tx_.acquire(int2(DOF_BOKEH_LUT_SIZE), GPU_RG16F); + bokeh_scatter_lut_tx_.acquire(int2(DOF_BOKEH_LUT_SIZE), GPU_R16F); + bokeh_resolve_lut_tx_.acquire(int2(DOF_MAX_SLIGHT_FOCUS_RADIUS * 2 + 1), GPU_R16F); + + DRW_draw_pass(bokeh_lut_ps_); + } + { + setup_color_tx_.acquire(half_res, GPU_RGBA16F); + setup_coc_tx_.acquire(half_res, GPU_R16F); + + DRW_draw_pass(setup_ps_); + } + { + stabilize_output_tx_.acquire(half_res, GPU_RGBA16F); + stabilize_valid_history_ = !dof_buffer.stabilize_history_tx_.ensure_2d(GPU_RGBA16F, + half_res); + + if (stabilize_valid_history_ == false) { + /* Avoid uninitialized memory that can contain NaNs. */ + dof_buffer.stabilize_history_tx_.clear(float4(0.0f)); + } + + stabilize_input_ = dof_buffer.stabilize_history_tx_; + /* Outputs to reduced_*_tx_ mip 0. */ + DRW_draw_pass(stabilize_ps_); + + /* WATCH(fclem): Swap Texture an TextureFromPool internal GPUTexture in order to reuse + * the one that we just consumed. */ + TextureFromPool::swap(stabilize_output_tx_, dof_buffer.stabilize_history_tx_); + + /* Used by stabilize pass. */ + stabilize_output_tx_.release(); + setup_color_tx_.release(); + } + { + DRW_stats_group_start("Tile Prepare"); + + /* WARNING: If format changes, make sure dof_tile_* GLSL constants are properly encoded. */ + tiles_fg_tx_.previous().acquire(tile_res, GPU_R11F_G11F_B10F); + tiles_bg_tx_.previous().acquire(tile_res, GPU_R11F_G11F_B10F); + tiles_fg_tx_.current().acquire(tile_res, GPU_R11F_G11F_B10F); + tiles_bg_tx_.current().acquire(tile_res, GPU_R11F_G11F_B10F); + + DRW_draw_pass(tiles_flatten_ps_); + + /* Used by tile_flatten and stabilize_ps pass. */ + setup_coc_tx_.release(); + + /* Error introduced by gather center jittering. */ + const float error_multiplier = 1.0f + 1.0f / (DOF_GATHER_RING_COUNT + 0.5f); + int dilation_end_radius = ceilf((fx_max_coc_ * error_multiplier) / (DOF_TILES_SIZE * 2)); + + /* Run dilation twice. One for minmax and one for minabs. */ + for (int pass = 0; pass < 2; pass++) { + /* This algorithm produce the exact dilation radius by dividing it in multiple passes. */ + int dilation_radius = 0; + while (dilation_radius < dilation_end_radius) { + int remainder = dilation_end_radius - dilation_radius; + /* Do not step over any unvisited tile. */ + int max_multiplier = dilation_radius + 1; + + int ring_count = min_ii(DOF_DILATE_RING_COUNT, ceilf(remainder / (float)max_multiplier)); + int multiplier = min_ii(max_multiplier, floorf(remainder / (float)ring_count)); + + dilation_radius += ring_count * multiplier; + + tiles_dilate_ring_count_ = ring_count; + tiles_dilate_ring_width_mul_ = multiplier; + + tiles_fg_tx_.swap(); + tiles_bg_tx_.swap(); + + DRW_draw_pass((pass == 0) ? tiles_dilate_minmax_ps_ : tiles_dilate_minabs_ps_); + } + } + + tiles_fg_tx_.previous().release(); + tiles_bg_tx_.previous().release(); + + DRW_stats_group_end(); + } + + downsample_tx_.acquire(quarter_res, GPU_RGBA16F); + + DRW_draw_pass(downsample_ps_); + + scatter_fg_indirect_buf_.clear_to_zero(); + scatter_bg_indirect_buf_.clear_to_zero(); + + DRW_draw_pass(reduce_ps_); + + /* Used by reduce pass. */ + downsample_tx_.release(); + + DRW_stats_group_end(); + } + + for (int is_background = 0; is_background < 2; is_background++) { + DRW_stats_group_start(is_background ? "Background Convolution" : "Foreground Convolution"); + + SwapChain<TextureFromPool, 2> &color_tx = is_background ? color_bg_tx_ : color_fg_tx_; + SwapChain<TextureFromPool, 2> &weight_tx = is_background ? weight_bg_tx_ : weight_fg_tx_; + Framebuffer &scatter_fb = is_background ? scatter_bg_fb_ : scatter_fg_fb_; + DRWPass *gather_ps = is_background ? gather_bg_ps_ : gather_fg_ps_; + DRWPass *filter_ps = is_background ? filter_bg_ps_ : filter_fg_ps_; + DRWPass *scatter_ps = is_background ? scatter_bg_ps_ : scatter_fg_ps_; + + color_tx.current().acquire(half_res, GPU_RGBA16F); + weight_tx.current().acquire(half_res, GPU_R16F); + occlusion_tx_.acquire(half_res, GPU_RG16F); + + DRW_draw_pass(gather_ps); + + { + /* Filtering pass. */ + color_tx.swap(); + weight_tx.swap(); + + color_tx.current().acquire(half_res, GPU_RGBA16F); + weight_tx.current().acquire(half_res, GPU_R16F); + + DRW_draw_pass(filter_ps); + + color_tx.previous().release(); + weight_tx.previous().release(); + } + + GPU_memory_barrier(GPU_BARRIER_FRAMEBUFFER); + + scatter_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_tx.current())); + + GPU_framebuffer_bind(scatter_fb); + DRW_draw_pass(scatter_ps); + + /* Used by scatter pass. */ + occlusion_tx_.release(); + + DRW_stats_group_end(); + } + { + DRW_stats_group_start("Hole Fill"); + + bokeh_gather_lut_tx_.release(); + bokeh_scatter_lut_tx_.release(); + + hole_fill_color_tx_.acquire(half_res, GPU_RGBA16F); + hole_fill_weight_tx_.acquire(half_res, GPU_R16F); + + DRW_draw_pass(hole_fill_ps_); + + /* NOTE: We do not filter the hole-fill pass as effect is likely to not be noticeable. */ + + DRW_stats_group_end(); + } + { + DRW_stats_group_start("Resolve"); + + resolve_stable_color_tx_ = dof_buffer.stabilize_history_tx_; + + DRW_draw_pass(resolve_ps_); + + color_bg_tx_.current().release(); + color_fg_tx_.current().release(); + weight_bg_tx_.current().release(); + weight_fg_tx_.current().release(); + tiles_fg_tx_.current().release(); + tiles_bg_tx_.current().release(); + hole_fill_color_tx_.release(); + hole_fill_weight_tx_.release(); + bokeh_resolve_lut_tx_.release(); + + DRW_stats_group_end(); + } + + DRW_stats_group_end(); + + /* Swap buffers so that next effect has the right input. */ + SWAP(GPUTexture *, *input_tx, *output_tx); +} + +/** \} */ + +} // namespace blender::eevee
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/eevee_depth_of_field.hh b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.hh new file mode 100644 index 00000000000..8c291b241bd --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_depth_of_field.hh @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * Depth of field post process effect. + * + * There are 2 methods to achieve this effect. + * - The first uses projection matrix offsetting and sample accumulation to give + * reference quality depth of field. But this needs many samples to hide the + * under-sampling. + * - The second one is a post-processing based one. It follows the + * implementation described in the presentation + * "Life of a Bokeh - Siggraph 2018" from Guillaume Abadie. + * There are some difference with our actual implementation that prioritize quality. + */ + +#pragma once + +#include "eevee_shader_shared.hh" + +namespace blender::eevee { + +class Instance; + +/* -------------------------------------------------------------------- */ +/** \name Depth of field + * \{ */ + +struct DepthOfFieldBuffer { + /** + * Per view history texture for stabilize pass. + * Swapped with stabilize_output_tx_ in order to reuse the previous history during DoF + * processing. + * Note this should be private as its inner working only concerns the Depth Of Field + * implementation. The view itself should not touch it. + */ + Texture stabilize_history_tx_ = {"dof_taa"}; +}; + +class DepthOfField { + private: + class Instance &inst_; + + /** Samplers */ + static constexpr eGPUSamplerState gather_bilinear = GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER; + static constexpr eGPUSamplerState gather_nearest = GPU_SAMPLER_MIPMAP; + + /** Input/Output texture references. */ + GPUTexture *input_color_tx_ = nullptr; + GPUTexture *output_color_tx_ = nullptr; + + /** Bokeh LUT precompute pass. */ + TextureFromPool bokeh_gather_lut_tx_ = {"dof_bokeh_gather_lut"}; + TextureFromPool bokeh_resolve_lut_tx_ = {"dof_bokeh_resolve_lut"}; + TextureFromPool bokeh_scatter_lut_tx_ = {"dof_bokeh_scatter_lut"}; + DRWPass *bokeh_lut_ps_ = nullptr; + + /** Outputs half-resolution color and Circle Of Confusion. */ + TextureFromPool setup_coc_tx_ = {"dof_setup_coc"}; + TextureFromPool setup_color_tx_ = {"dof_setup_color"}; + int3 dispatch_setup_size_ = int3(-1); + DRWPass *setup_ps_ = nullptr; + + /** Allocated because we need mip chain. Which isn't supported by TextureFromPool. */ + Texture reduced_coc_tx_ = {"dof_reduced_coc"}; + Texture reduced_color_tx_ = {"dof_reduced_color"}; + + /** Stabilization (flicker attenuation) of Color and CoC output of the setup pass. */ + TextureFromPool stabilize_output_tx_ = {"dof_taa"}; + GPUTexture *stabilize_input_ = nullptr; + bool1 stabilize_valid_history_ = false; + int3 dispatch_stabilize_size_ = int3(-1); + DRWPass *stabilize_ps_ = nullptr; + + /** 1/4th res color buffer used to speedup the local contrast test in the first reduce pass. */ + TextureFromPool downsample_tx_ = {"dof_downsample"}; + int3 dispatch_downsample_size_ = int3(-1); + DRWPass *downsample_ps_ = nullptr; + + /** Create mip-mapped color & COC textures for gather passes as well as scatter rect list. */ + DepthOfFieldScatterListBuf scatter_fg_list_buf_; + DepthOfFieldScatterListBuf scatter_bg_list_buf_; + DrawIndirectBuf scatter_fg_indirect_buf_; + DrawIndirectBuf scatter_bg_indirect_buf_; + int3 dispatch_reduce_size_ = int3(-1); + DRWPass *reduce_ps_ = nullptr; + + /** Outputs min & max COC in each 8x8 half res pixel tiles (so 1/16th of full resolution). */ + SwapChain<TextureFromPool, 2> tiles_fg_tx_; + SwapChain<TextureFromPool, 2> tiles_bg_tx_; + int3 dispatch_tiles_flatten_size_ = int3(-1); + DRWPass *tiles_flatten_ps_ = nullptr; + + /** Dilates the min & max CoCs to cover maximum COC values. */ + int tiles_dilate_ring_count_ = -1; + int tiles_dilate_ring_width_mul_ = -1; + int3 dispatch_tiles_dilate_size_ = int3(-1); + DRWPass *tiles_dilate_minmax_ps_ = nullptr; + DRWPass *tiles_dilate_minabs_ps_ = nullptr; + + /** Gather convolution for low intensity pixels and low contrast areas. */ + SwapChain<TextureFromPool, 2> color_bg_tx_; + SwapChain<TextureFromPool, 2> color_fg_tx_; + SwapChain<TextureFromPool, 2> weight_bg_tx_; + SwapChain<TextureFromPool, 2> weight_fg_tx_; + TextureFromPool occlusion_tx_ = {"dof_occlusion"}; + int3 dispatch_gather_size_ = int3(-1); + DRWPass *gather_fg_ps_ = nullptr; + DRWPass *gather_bg_ps_ = nullptr; + + /** Hole-fill convolution: Gather pass meant to fill areas of foreground dis-occlusion. */ + TextureFromPool hole_fill_color_tx_ = {"dof_color_hole_fill"}; + TextureFromPool hole_fill_weight_tx_ = {"dof_weight_hole_fill"}; + DRWPass *hole_fill_ps_ = nullptr; + + /** Small Filter pass to reduce noise out of gather passes. */ + int3 dispatch_filter_size_ = int3(-1); + DRWPass *filter_fg_ps_ = nullptr; + DRWPass *filter_bg_ps_ = nullptr; + + /** Scatter convolution: A quad is emitted for every 4 bright enough half pixels. */ + Framebuffer scatter_fg_fb_ = {"dof_scatter_fg"}; + Framebuffer scatter_bg_fb_ = {"dof_scatter_bg"}; + DRWPass *scatter_fg_ps_ = nullptr; + DRWPass *scatter_bg_ps_ = nullptr; + + /** Recombine the results and also perform a slight out of focus gather. */ + GPUTexture *resolve_stable_color_tx_ = nullptr; + int3 dispatch_resolve_size_ = int3(-1); + DRWPass *resolve_ps_ = nullptr; + + DepthOfFieldDataBuf data_; + + /** Scene settings that are immutable. */ + float user_overblur_; + float fx_max_coc_; + /** Use jittered depth of field where we randomize camera location. */ + bool do_jitter_; + + /** Circle of Confusion radius for FX DoF passes. Is in view X direction in [0..1] range. */ + float fx_radius_; + /** Circle of Confusion radius for jittered DoF. Is in view X direction in [0..1] range. */ + float jitter_radius_; + /** Focus distance in view space. */ + float focus_distance_; + /** Extent of the input buffer. */ + int2 extent_; + + public: + DepthOfField(Instance &inst) : inst_(inst){}; + ~DepthOfField(){}; + + void init(); + + void sync(); + + /** + * Apply Depth Of Field jittering to the view and projection matrices.. + */ + void jitter_apply(float4x4 &winmat, float4x4 &viewmat); + + /** + * Will swap input and output texture if rendering happens. The actual output of this function + * is in input_tx. + */ + void render(GPUTexture **input_tx, GPUTexture **output_tx, DepthOfFieldBuffer &dof_buffer); + + bool postfx_enabled() const + { + return fx_radius_ > 0.0f; + } + + private: + void bokeh_lut_pass_sync(); + void setup_pass_sync(); + void stabilize_pass_sync(); + void downsample_pass_sync(); + void reduce_pass_sync(); + void tiles_flatten_pass_sync(); + void tiles_dilate_pass_sync(); + void gather_pass_sync(); + void filter_pass_sync(); + void scatter_pass_sync(); + void hole_fill_pass_sync(); + void resolve_pass_sync(); + + void update_sample_table(); +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_film.cc b/source/blender/draw/engines/eevee_next/eevee_film.cc index 49f43265aa8..b3fbe088471 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.cc +++ b/source/blender/draw/engines/eevee_next/eevee_film.cc @@ -183,20 +183,17 @@ void Film::init(const int2 &extent, const rcti *output_rect) * Using the render pass ensure we store the center depth. */ render_passes |= EEVEE_RENDER_PASS_Z; } - /* TEST */ - render_passes |= EEVEE_RENDER_PASS_VECTOR; } else { /* Render Case. */ render_passes = eViewLayerEEVEEPassType(inst_.view_layer->eevee.render_passes); - render_passes |= EEVEE_RENDER_PASS_COMBINED; - #define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \ SET_FLAG_FROM_TEST(render_passes, \ (inst_.view_layer->passflag & SCE_PASS_##name_legacy) != 0, \ EEVEE_RENDER_PASS_##name_eevee); + ENABLE_FROM_LEGACY(COMBINED, COMBINED) ENABLE_FROM_LEGACY(Z, Z) ENABLE_FROM_LEGACY(MIST, MIST) ENABLE_FROM_LEGACY(NORMAL, NORMAL) @@ -209,6 +206,7 @@ void Film::init(const int2 &extent, const rcti *output_rect) ENABLE_FROM_LEGACY(DIFFUSE_DIRECT, DIFFUSE_LIGHT) ENABLE_FROM_LEGACY(GLOSSY_DIRECT, SPECULAR_LIGHT) ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT) + ENABLE_FROM_LEGACY(VECTOR, VECTOR) #undef ENABLE_FROM_LEGACY } @@ -216,6 +214,11 @@ void Film::init(const int2 &extent, const rcti *output_rect) /* Filter obsolete passes. */ render_passes &= ~(EEVEE_RENDER_PASS_UNUSED_8 | EEVEE_RENDER_PASS_BLOOM); + if (scene_eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) { + /* Disable motion vector pass if motion blur is enabled. */ + render_passes &= ~EEVEE_RENDER_PASS_VECTOR; + } + /* TODO(@fclem): Can't we rely on depsgraph update notification? */ if (assign_if_different(enabled_passes_, render_passes)) { sampling.reset(); @@ -383,7 +386,7 @@ void Film::sync() DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*velocity.camera_steps[STEP_CURRENT])); DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*velocity.camera_steps[step_next])); DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &rbuffers.depth_tx); - DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &rbuffers.combined_tx); + DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &combined_final_tx_); DRW_shgroup_uniform_texture_ref(grp, "normal_tx", &rbuffers.normal_tx); DRW_shgroup_uniform_texture_ref(grp, "vector_tx", &rbuffers.vector_tx); DRW_shgroup_uniform_texture_ref(grp, "diffuse_light_tx", &rbuffers.diffuse_light_tx); @@ -400,10 +403,10 @@ void Film::sync() /* NOTE(@fclem): 16 is the max number of sampled texture in many implementations. * If we need more, we need to pack more of the similar passes in the same textures as arrays or * use image binding instead. */ - DRW_shgroup_uniform_image_ref(grp, "in_weight_img", &weight_src_tx_); - DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &weight_dst_tx_); - DRW_shgroup_uniform_texture_ref_ex(grp, "in_combined_tx", &combined_src_tx_, filter); - DRW_shgroup_uniform_image_ref(grp, "out_combined_img", &combined_dst_tx_); + DRW_shgroup_uniform_image_ref(grp, "in_weight_img", &weight_tx_.current()); + DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &weight_tx_.next()); + DRW_shgroup_uniform_texture_ref_ex(grp, "in_combined_tx", &combined_tx_.current(), filter); + DRW_shgroup_uniform_image_ref(grp, "out_combined_img", &combined_tx_.next()); DRW_shgroup_uniform_image_ref(grp, "depth_img", &depth_tx_); DRW_shgroup_uniform_image_ref(grp, "color_accum_img", &color_accum_tx_); DRW_shgroup_uniform_image_ref(grp, "value_accum_img", &value_accum_tx_); @@ -458,6 +461,10 @@ float2 Film::pixel_jitter_get() const eViewLayerEEVEEPassType Film::enabled_passes_get() const { + if (inst_.is_viewport() && data_.use_reprojection) { + /* Enable motion vector rendering but not the accumulation buffer. */ + return enabled_passes_ | EEVEE_RENDER_PASS_VECTOR; + } return enabled_passes_; } @@ -476,7 +483,7 @@ void Film::update_sample_table() data_.samples_weight_total = 1.0f; data_.samples_len = 1; } - /* NOTE: Threshold determined by hand until we don't hit the assert bellow. */ + /* NOTE: Threshold determined by hand until we don't hit the assert below. */ else if (data_.filter_radius < 2.20f) { /* Small filter Size. */ int closest_index = 0; @@ -538,7 +545,7 @@ void Film::update_sample_table() } } -void Film::accumulate(const DRWView *view) +void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx) { if (inst_.is_viewport()) { DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); @@ -554,11 +561,7 @@ void Film::accumulate(const DRWView *view) update_sample_table(); - /* Need to update the static references as there could have change from a previous swap. */ - weight_src_tx_ = weight_tx_.current(); - weight_dst_tx_ = weight_tx_.next(); - combined_src_tx_ = combined_tx_.current(); - combined_dst_tx_ = combined_tx_.next(); + combined_final_tx_ = combined_final_tx; data_.display_only = false; data_.push_update(); @@ -580,17 +583,13 @@ void Film::display() BLI_assert(inst_.is_viewport()); /* Acquire dummy render buffers for correct binding. They will not be used. */ - inst_.render_buffers.acquire(int2(1), (void *)this); + inst_.render_buffers.acquire(int2(1)); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent)); - /* Need to update the static references as there could have change from a previous swap. */ - weight_src_tx_ = weight_tx_.current(); - weight_dst_tx_ = weight_tx_.next(); - combined_src_tx_ = combined_tx_.current(); - combined_dst_tx_ = combined_tx_.next(); + combined_final_tx_ = inst_.render_buffers.combined_tx; data_.display_only = true; data_.push_update(); diff --git a/source/blender/draw/engines/eevee_next/eevee_film.hh b/source/blender/draw/engines/eevee_next/eevee_film.hh index 1165b9a4c12..3e368782d31 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.hh +++ b/source/blender/draw/engines/eevee_next/eevee_film.hh @@ -40,6 +40,9 @@ class Film { private: Instance &inst_; + /** Incoming combined buffer with post FX applied (motion blur + depth of field). */ + GPUTexture *combined_final_tx_ = nullptr; + /** Main accumulation textures containing every render-pass except depth and combined. */ Texture color_accum_tx_; Texture value_accum_tx_; @@ -47,14 +50,8 @@ class Film { Texture depth_tx_; /** Combined "Color" buffer. Double buffered to allow re-projection. */ SwapChain<Texture, 2> combined_tx_; - /** Static reference as SwapChain does not actually move the objects when swapping. */ - GPUTexture *combined_src_tx_ = nullptr; - GPUTexture *combined_dst_tx_ = nullptr; /** Weight buffers. Double buffered to allow updating it during accumulation. */ SwapChain<Texture, 2> weight_tx_; - /** Static reference as SwapChain does not actually move the objects when swapping. */ - GPUTexture *weight_src_tx_ = nullptr; - GPUTexture *weight_dst_tx_ = nullptr; /** User setting to disable reprojection. Useful for debugging or have a more precise render. */ bool force_disable_reprojection_ = false; @@ -74,7 +71,7 @@ class Film { void end_sync(); /** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */ - void accumulate(const DRWView *view); + void accumulate(const DRWView *view, GPUTexture *combined_final_tx); /** Blit to display. No rendered sample needed. */ void display(); @@ -82,6 +79,7 @@ class Film { float *read_pass(eViewLayerEEVEEPassType pass_type); float *read_aov(ViewLayerAOV *aov); + /** Returns shading views internal resolution. */ int2 render_extent_get() const { return data_.render_extent; diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 9f8cf6dc6ba..df7a9ba7702 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -60,6 +60,9 @@ void Instance::init(const int2 &output_res, sampling.init(scene); camera.init(); film.init(output_res, output_rect); + velocity.init(); + depth_of_field.init(); + motion_blur.init(); main_view.init(); } @@ -92,15 +95,15 @@ void Instance::update_eval_members() void Instance::begin_sync() { materials.begin_sync(); - velocity.begin_sync(); + velocity.begin_sync(); /* NOTE: Also syncs camera. */ gpencil_engine_enabled = false; - render_buffers.sync(); + depth_of_field.sync(); + motion_blur.sync(); pipelines.sync(); main_view.sync(); world.sync(); - camera.sync(); film.sync(); } @@ -212,22 +215,12 @@ void Instance::render_sample() sampling.step(); main_view.render(); -} - -/** \} */ -/* -------------------------------------------------------------------- */ -/** \name Interface - * \{ */ + motion_blur.step(); +} -void Instance::render_frame(RenderLayer *render_layer, const char *view_name) +void Instance::render_read_result(RenderLayer *render_layer, const char *view_name) { - while (!sampling.finished()) { - this->render_sample(); - /* TODO(fclem) print progression. */ - } - - /* Read Results. */ eViewLayerEEVEEPassType pass_bits = film.enabled_passes_get(); for (auto i : IndexRange(EEVEE_RENDER_PASS_MAX_BIT)) { eViewLayerEEVEEPassType pass_type = eViewLayerEEVEEPassType(pass_bits & (1 << i)); @@ -240,7 +233,6 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name) if (rp) { float *result = film.read_pass(pass_type); if (result) { - std::cout << "read " << pass_name << std::endl; BLI_mutex_lock(&render->update_render_passes_mutex); /* WORKAROUND: We use texture read to avoid using a framebuffer to get the render result. * However, on some implementation, we need a buffer with a few extra bytes for the read to @@ -252,6 +244,45 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name) } } } + + /* The vector pass is initialized to weird values. Set it to neutral value if not rendered. */ + if ((pass_bits & EEVEE_RENDER_PASS_VECTOR) == 0) { + const char *vector_pass_name = Film::pass_to_render_pass_name(EEVEE_RENDER_PASS_VECTOR); + RenderPass *vector_rp = RE_pass_find_by_name(render_layer, vector_pass_name, view_name); + if (vector_rp) { + memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Interface + * \{ */ + +void Instance::render_frame(RenderLayer *render_layer, const char *view_name) +{ + while (!sampling.finished()) { + this->render_sample(); + + /* TODO(fclem) print progression. */ +#if 0 + /* TODO(fclem): Does not currently work. But would be better to just display to 2D view like + * cycles does. */ + if (G.background == false && first_read) { + /* Allow to preview the first sample. */ + /* TODO(fclem): Might want to not do this during animation render to avoid too much stall. */ + this->render_read_result(render_layer, view_name); + first_read = false; + DRW_render_context_disable(render->re); + /* Allow the 2D viewport to grab the ticket mutex to display the render. */ + DRW_render_context_enable(render->re); + } +#endif + } + + this->render_read_result(render_layer, view_name); } void Instance::draw_viewport(DefaultFramebufferList *dfbl) @@ -260,7 +291,10 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl) render_sample(); velocity.step_swap(); - if (!sampling.finished_viewport()) { + /* Do not request redraw during viewport animation to lock the framerate to the animation + * playback rate. This is in order to preserve motion blur aspect and also to avoid TAA reset + * that can show flickering. */ + if (!sampling.finished_viewport() && !DRW_state_is_playback()) { DRW_viewport_request_redraw(); } diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 1efda769648..60dffd7c5ec 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -16,8 +16,10 @@ #include "DRW_render.h" #include "eevee_camera.hh" +#include "eevee_depth_of_field.hh" #include "eevee_film.hh" #include "eevee_material.hh" +#include "eevee_motion_blur.hh" #include "eevee_pipeline.hh" #include "eevee_renderbuffers.hh" #include "eevee_sampling.hh" @@ -34,6 +36,7 @@ namespace blender::eevee { */ class Instance { friend VelocityModule; + friend MotionBlurModule; public: ShaderModule &shaders; @@ -41,6 +44,8 @@ class Instance { MaterialModule materials; PipelineModule pipelines; VelocityModule velocity; + MotionBlurModule motion_blur; + DepthOfField depth_of_field; Sampling sampling; Camera camera; Film film; @@ -76,6 +81,8 @@ class Instance { materials(*this), pipelines(*this), velocity(*this), + motion_blur(*this), + depth_of_field(*this), sampling(*this), camera(*this), film(*this), @@ -138,6 +145,7 @@ class Instance { RenderEngine *engine, Depsgraph *depsgraph); void render_sample(); + void render_read_result(RenderLayer *render_layer, const char *view_name); void mesh_sync(Object *ob, ObjectHandle &ob_handle); diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc new file mode 100644 index 00000000000..660eb9f1e22 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + */ + +// #include "BLI_map.hh" +#include "DEG_depsgraph_query.h" + +#include "eevee_instance.hh" +#include "eevee_motion_blur.hh" +// #include "eevee_sampling.hh" +// #include "eevee_shader_shared.hh" +// #include "eevee_velocity.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name MotionBlurModule + * + * \{ */ + +void MotionBlurModule::init() +{ + const Scene *scene = inst_.scene; + + enabled_ = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0; + + if (!enabled_) { + motion_blur_fx_enabled_ = false; + return; + } + + /* Take into account the steps needed for fx motion blur. */ + int steps_count = max_ii(1, scene->eevee.motion_blur_steps) * 2 + 1; + + time_steps_.resize(steps_count); + + initial_frame_ = scene->r.cfra; + initial_subframe_ = scene->r.subframe; + frame_time_ = initial_frame_ + initial_subframe_; + shutter_position_ = scene->eevee.motion_blur_position; + shutter_time_ = scene->eevee.motion_blur_shutter; + + data_.depth_scale = scene->eevee.motion_blur_depth_scale; + motion_blur_fx_enabled_ = true; /* TODO(fclem): UI option. */ + + /* Viewport stops here. We only do Post-FX motion blur. */ + if (inst_.is_viewport()) { + enabled_ = false; + return; + } + + /* Without this there is the possibility of the curve table not being allocated. */ + BKE_curvemapping_changed((struct CurveMapping *)&scene->r.mblur_shutter_curve, false); + + Vector<float> cdf(CM_TABLE); + Sampling::cdf_from_curvemapping(scene->r.mblur_shutter_curve, cdf); + Sampling::cdf_invert(cdf, time_steps_); + + for (float &time : time_steps_) { + time = this->shutter_time_to_scene_time(time); + } + + step_id_ = 1; + + if (motion_blur_fx_enabled_) { + /* A bit weird but we have to sync the first 2 steps here because the step() + * function is only called after rendering a sample. */ + inst_.velocity.step_sync(STEP_PREVIOUS, time_steps_[0]); + inst_.velocity.step_sync(STEP_NEXT, time_steps_[2]); + } + inst_.set_time(time_steps_[1]); +} + +/* Runs after rendering a sample. */ +void MotionBlurModule::step() +{ + if (!enabled_) { + return; + } + + if (inst_.sampling.finished()) { + /* Restore original frame number. This is because the render pipeline expects it. */ + RE_engine_frame_set(inst_.render, initial_frame_, initial_subframe_); + } + else if (inst_.sampling.do_render_sync()) { + /* Time to change motion step. */ + BLI_assert(time_steps_.size() > step_id_ + 2); + step_id_ += 2; + + if (motion_blur_fx_enabled_) { + inst_.velocity.step_swap(); + inst_.velocity.step_sync(eVelocityStep::STEP_NEXT, time_steps_[step_id_ + 1]); + } + inst_.set_time(time_steps_[step_id_]); + } +} + +float MotionBlurModule::shutter_time_to_scene_time(float time) +{ + switch (shutter_position_) { + case SCE_EEVEE_MB_START: + /* No offset. */ + break; + case SCE_EEVEE_MB_CENTER: + time -= 0.5f; + break; + case SCE_EEVEE_MB_END: + time -= 1.0; + break; + default: + BLI_assert(!"Invalid motion blur position enum!"); + break; + } + time *= shutter_time_; + time += frame_time_; + return time; +} + +void MotionBlurModule::sync() +{ + /* Disable motion blur in viewport when changing camera projection type. + * Avoids really high velocities. */ + if (inst_.velocity.camera_changed_projection()) { + motion_blur_fx_enabled_ = false; + } + + if (!motion_blur_fx_enabled_) { + return; + } + + eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT; + RenderBuffers &render_buffers = inst_.render_buffers; + + { + /* Create max velocity tiles. */ + DRW_PASS_CREATE(tiles_flatten_ps_, DRW_STATE_NO_DRAW); + eShaderType shader = (inst_.is_viewport()) ? MOTION_BLUR_TILE_FLATTEN_VIEWPORT : + MOTION_BLUR_TILE_FLATTEN_RENDER; + GPUShader *sh = inst_.shaders.static_shader_get(shader); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_flatten_ps_); + inst_.velocity.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &render_buffers.depth_tx); + DRW_shgroup_uniform_image_ref(grp, "velocity_img", &render_buffers.vector_tx); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_img", &tiles_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_flatten_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_TEXTURE_FETCH); + } + { + /* Expand max velocity tiles by spreading them in their neighborhood. */ + DRW_PASS_CREATE(tiles_dilate_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_TILE_DILATE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_dilate_ps_); + DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_dilate_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } + { + /* Do the motion blur gather algorithm. */ + DRW_PASS_CREATE(gather_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_GATHER); + DRWShadingGroup *grp = DRW_shgroup_create(sh, gather_ps_); + inst_.sampling.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_); + DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocity_tx", &render_buffers.vector_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "in_color_tx", &input_color_tx_, no_filter); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &output_color_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_gather_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + } +} + +void MotionBlurModule::render(GPUTexture **input_tx, GPUTexture **output_tx) +{ + if (!motion_blur_fx_enabled_) { + return; + } + + const Texture &depth_tx = inst_.render_buffers.depth_tx; + + int2 extent = {depth_tx.width(), depth_tx.height()}; + int2 tiles_extent = math::divide_ceil(extent, int2(MOTION_BLUR_TILE_SIZE)); + + if (inst_.is_viewport()) { + float frame_delta = fabsf(inst_.velocity.step_time_delta_get(STEP_PREVIOUS, STEP_CURRENT)); + /* Avoid highly disturbing blurs, during navigation with high shutter time. */ + if (frame_delta > 0.0f && !DRW_state_is_navigating()) { + /* Rescale motion blur intensity to be shutter time relative and avoid long streak when we + * have frame skipping. Always try to stick to what the render frame would look like. */ + data_.motion_scale = float2(shutter_time_ / frame_delta); + } + else { + /* There is no time change. Motion only comes from viewport navigation and object transform. + * Apply motion blur as smoothing and only blur towards last frame. */ + data_.motion_scale = float2(1.0f, 0.0f); + + if (was_navigating_ != DRW_state_is_navigating()) { + /* Special case for navigation events that only last for one frame (for instance mouse + * scroll for zooming). For this case we have to wait for the next frame before enabling + * the navigation motion blur. */ + was_navigating_ = DRW_state_is_navigating(); + return; + } + } + was_navigating_ = DRW_state_is_navigating(); + + /* Change texture swizzling to avoid complexity in gather pass shader. */ + GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgrg"); + } + else { + data_.motion_scale = float2(1.0f); + } + /* Second motion vector is stored inverted. */ + data_.motion_scale.y = -data_.motion_scale.y; + data_.target_size_inv = 1.0f / float2(extent); + data_.push_update(); + + input_color_tx_ = *input_tx; + output_color_tx_ = *output_tx; + + dispatch_flatten_size_ = int3(tiles_extent, 1); + dispatch_dilate_size_ = int3(math::divide_ceil(tiles_extent, int2(MOTION_BLUR_GROUP_SIZE)), 1); + dispatch_gather_size_ = int3(math::divide_ceil(extent, int2(MOTION_BLUR_GROUP_SIZE)), 1); + + DRW_stats_group_start("Motion Blur"); + + tiles_tx_.acquire(tiles_extent, GPU_RGBA16F); + + GPU_storagebuf_clear_to_zero(tile_indirection_buf_); + + DRW_draw_pass(tiles_flatten_ps_); + DRW_draw_pass(tiles_dilate_ps_); + DRW_draw_pass(gather_ps_); + + tiles_tx_.release(); + + DRW_stats_group_end(); + + if (inst_.is_viewport()) { + /* Reset swizzle since this texture might be reused in other places. */ + GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgba"); + } + + /* Swap buffers so that next effect has the right input. */ + *input_tx = output_color_tx_; + *output_tx = input_color_tx_; +} + +/** \} */ + +} // namespace blender::eevee
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh new file mode 100644 index 00000000000..310e94a702b --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * Motion blur is done by accumulating scene samples over shutter time. + * Since the number of step is discrete, quite low, and not per pixel randomized, + * we couple this with a post processing motion blur. + * + * The post-fx motion blur is done in two directions, from the previous step and to the next. + * + * For a scene with 3 motion steps, a flat shutter curve and shutter time of 2 frame + * centered on frame we have: + * + * |--------------------|--------------------| + * -1 0 1 Frames + * + * |-------------|-------------|-------------| + * 1 2 3 Motion steps + * + * |------|------|------|------|------|------| + * 0 1 2 4 5 6 7 Time Steps + * + * |-------------| One motion step blurs this range. + * -1 | +1 Objects and geometry steps are recorded here. + * 0 Scene is rendered here. + * + * Since motion step N and N+1 share one time step we reuse it to avoid an extra scene evaluation. + * + * Note that we have to evaluate -1 and +1 time steps before rendering so eval order is -1, +1, 0. + * This is because all GPUBatches from the DRWCache are being free when changing a frame. + * + * For viewport, we only have the current and previous step data to work with. So we center the + * blur on the current frame and extrapolate the motion. + * + * The Post-FX motion blur is based on: + * "A Fast and Stable Feature-Aware Motion Blur Filter" + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + */ + +#pragma once + +#include "BLI_map.hh" +#include "DEG_depsgraph_query.h" + +#include "eevee_sampling.hh" +#include "eevee_shader_shared.hh" +#include "eevee_velocity.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name MotionBlur + * + * \{ */ + +/** + * Manages time-steps evaluations and accumulation Motion blur. + * Also handles Post process motion blur. + */ +class MotionBlurModule { + private: + Instance &inst_; + + /** + * Array containing all steps (in scene time) we need to evaluate (not render). + * Only odd steps are rendered. The even ones are evaluated for fx motion blur. + */ + Vector<float> time_steps_; + + /** Copy of input frame and sub-frame to restore after render. */ + int initial_frame_; + float initial_subframe_; + /** Time of the frame we are rendering. */ + float frame_time_; + /** Enum controlling when the shutter opens. See SceneEEVEE.motion_blur_position. */ + int shutter_position_; + /** Time in scene frame the shutter is open. Controls the amount of blur. */ + float shutter_time_; + + /** True if motion blur is enabled as a module. */ + bool enabled_ = false; + /** True if motion blur post-fx is enabled. */ + float motion_blur_fx_enabled_ = false; + /** True if last viewport redraw state was already in navigation state. */ + bool was_navigating_ = false; + + int step_id_ = 0; + + /** Velocity tiles used to guide and speedup the gather pass. */ + TextureFromPool tiles_tx_; + + GPUTexture *input_color_tx_ = nullptr; + GPUTexture *output_color_tx_ = nullptr; + + DRWPass *tiles_flatten_ps_ = nullptr; + DRWPass *tiles_dilate_ps_ = nullptr; + DRWPass *gather_ps_ = nullptr; + + MotionBlurTileIndirectionBuf tile_indirection_buf_; + MotionBlurDataBuf data_; + /** Dispatch size for full-screen passes. */ + int3 dispatch_flatten_size_ = int3(0); + int3 dispatch_dilate_size_ = int3(0); + int3 dispatch_gather_size_ = int3(0); + + public: + MotionBlurModule(Instance &inst) : inst_(inst){}; + ~MotionBlurModule(){}; + + void init(); + + void step(); + + void sync(); + + bool postfx_enabled() const + { + return motion_blur_fx_enabled_; + } + + void render(GPUTexture **input_tx, GPUTexture **output_tx); + + private: + float shutter_time_to_scene_time(float time); +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 214fe9c7153..db169ec361f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -162,6 +162,7 @@ DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat, DRWShadingGroup *ForwardPipeline::material_transparent_add(::Material *blender_mat, GPUMaterial *gpumat) { + RenderBuffers &rbufs = inst_.render_buffers; // LightModule &lights = inst_.lights; // LightProbeModule &lightprobes = inst_.lightprobes; // RaytracingModule &raytracing = inst_.raytracing; @@ -191,6 +192,22 @@ DRWShadingGroup *ForwardPipeline::material_transparent_add(::Material *blender_m // DRW_shgroup_uniform_block(grp, "hiz_buf", inst_.hiz.ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", inst_.hiz_front.texture_ref_get()); // } + { + /* TODO(fclem): This is not needed. This is only to please the OpenGL debug Layer. + * If we are to introduce transparency render-passes support, it would be through a separate + * pass. */ + /* AOVs. */ + DRW_shgroup_uniform_image_ref(grp, "aov_color_img", &rbufs.aov_color_tx); + DRW_shgroup_uniform_image_ref(grp, "aov_value_img", &rbufs.aov_value_tx); + DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info); + /* RenderPasses. */ + DRW_shgroup_uniform_image_ref(grp, "rp_normal_img", &rbufs.normal_tx); + DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_light_img", &rbufs.diffuse_light_tx); + DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_color_img", &rbufs.diffuse_color_tx); + DRW_shgroup_uniform_image_ref(grp, "rp_specular_light_img", &rbufs.specular_light_tx); + DRW_shgroup_uniform_image_ref(grp, "rp_specular_color_img", &rbufs.specular_color_tx); + DRW_shgroup_uniform_image_ref(grp, "rp_emission_img", &rbufs.emission_tx); + } DRWState state_disable = DRW_STATE_WRITE_DEPTH; DRWState state_enable = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc index c60054496c1..b69fde7b26c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc @@ -24,25 +24,7 @@ namespace blender::eevee { -void RenderBuffers::sync() -{ - depth_tx.sync(); - combined_tx.sync(); - - normal_tx.sync(); - vector_tx.sync(); - diffuse_light_tx.sync(); - diffuse_color_tx.sync(); - specular_light_tx.sync(); - specular_color_tx.sync(); - volume_light_tx.sync(); - emission_tx.sync(); - environment_tx.sync(); - shadow_tx.sync(); - ambient_occlusion_tx.sync(); -} - -void RenderBuffers::acquire(int2 extent, void *owner) +void RenderBuffers::acquire(int2 extent) { auto pass_extent = [&](eViewLayerEEVEEPassType pass_bit) -> int2 { /* Use dummy texture for disabled passes. Allows correct bindings. */ @@ -53,25 +35,26 @@ void RenderBuffers::acquire(int2 extent, void *owner) eGPUTextureFormat float_format = GPU_R16F; /* Depth and combined are always needed. */ - depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8, owner); - combined_tx.acquire(extent, color_format, owner); + depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8); + combined_tx.acquire(extent, color_format); - bool do_vector_render_pass = inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR; + bool do_vector_render_pass = (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) || + (inst_.motion_blur.postfx_enabled() && !inst_.is_viewport()); /* Only RG16F when only doing only reprojection or motion blur. */ eGPUTextureFormat vector_format = do_vector_render_pass ? GPU_RGBA16F : GPU_RG16F; /* TODO(fclem): Make vector pass allocation optional if no TAA or motion blur is needed. */ - vector_tx.acquire(extent, vector_format, owner); - - normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format, owner); - diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format, owner); - diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format, owner); - specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format, owner); - specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format, owner); - volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format, owner); - emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format, owner); - environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format, owner); - shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format, owner); - ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format, owner); + vector_tx.acquire(extent, vector_format); + + normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format); + diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format); + diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format); + specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format); + specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format); + volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format); + emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format); + environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format); + shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format); + ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format); const AOVsInfoData &aovs = inst_.film.aovs_info; aov_color_tx.ensure_2d_array( diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh index 8c91fed2f0f..787f5604aa4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh @@ -48,9 +48,8 @@ class RenderBuffers { public: RenderBuffers(Instance &inst) : inst_(inst){}; - void sync(); /* Acquires (also ensures) the render buffer before rendering to them. */ - void acquire(int2 extent, void *owner); + void acquire(int2 extent); void release(); }; diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.cc b/source/blender/draw/engines/eevee_next/eevee_sampling.cc index 1d320c75f16..76a0e98638b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sampling.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sampling.cc @@ -232,7 +232,7 @@ void Sampling::cdf_from_curvemapping(const CurveMapping &curve, Vector<float> &c BLI_assert(cdf.size() > 1); cdf[0] = 0.0f; /* Actual CDF evaluation. */ - for (int u : cdf.index_range()) { + for (int u : IndexRange(cdf.size() - 1)) { float x = (float)(u + 1) / (float)(cdf.size() - 1); cdf[u + 1] = cdf[u] + BKE_curvemapping_evaluateF(&curve, 0, x); } diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.hh b/source/blender/draw/engines/eevee_next/eevee_sampling.hh index c604ecef40b..be87ee74886 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sampling.hh +++ b/source/blender/draw/engines/eevee_next/eevee_sampling.hh @@ -27,11 +27,11 @@ class Sampling { Instance &inst_; /* Number of samples in the first ring of jittered depth of field. */ - constexpr static uint64_t dof_web_density_ = 6; + static constexpr uint64_t dof_web_density_ = 6; /* High number of sample for viewport infinite rendering. */ - constexpr static uint64_t infinite_sample_count_ = 0xFFFFFFu; + static constexpr uint64_t infinite_sample_count_ = 0xFFFFFFu; /* During interactive rendering, loop over the first few samples. */ - constexpr static uint64_t interactive_sample_max_ = 8; + static constexpr uint64_t interactive_sample_max_ = 8; /** 0 based current sample. Might not increase sequentially in viewport. */ uint64_t sample_ = 0; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 7db9692783a..357f2796a7e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -82,6 +82,48 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_film_frag"; case FILM_COMP: return "eevee_film_comp"; + case MOTION_BLUR_GATHER: + return "eevee_motion_blur_gather"; + case MOTION_BLUR_TILE_DILATE: + return "eevee_motion_blur_tiles_dilate"; + case MOTION_BLUR_TILE_FLATTEN_RENDER: + return "eevee_motion_blur_tiles_flatten_render"; + case MOTION_BLUR_TILE_FLATTEN_VIEWPORT: + return "eevee_motion_blur_tiles_flatten_viewport"; + case DOF_BOKEH_LUT: + return "eevee_depth_of_field_bokeh_lut"; + case DOF_DOWNSAMPLE: + return "eevee_depth_of_field_downsample"; + case DOF_FILTER: + return "eevee_depth_of_field_filter"; + case DOF_GATHER_FOREGROUND_LUT: + return "eevee_depth_of_field_gather_foreground_lut"; + case DOF_GATHER_FOREGROUND: + return "eevee_depth_of_field_gather_foreground_no_lut"; + case DOF_GATHER_BACKGROUND_LUT: + return "eevee_depth_of_field_gather_background_lut"; + case DOF_GATHER_BACKGROUND: + return "eevee_depth_of_field_gather_background_no_lut"; + case DOF_GATHER_HOLE_FILL: + return "eevee_depth_of_field_hole_fill"; + case DOF_REDUCE: + return "eevee_depth_of_field_reduce"; + case DOF_RESOLVE: + return "eevee_depth_of_field_resolve_no_lut"; + case DOF_RESOLVE_LUT: + return "eevee_depth_of_field_resolve_lut"; + case DOF_SETUP: + return "eevee_depth_of_field_setup"; + case DOF_SCATTER: + return "eevee_depth_of_field_scatter"; + case DOF_STABILIZE: + return "eevee_depth_of_field_stabilize"; + case DOF_TILES_DILATE_MINABS: + return "eevee_depth_of_field_tiles_dilate_minabs"; + case DOF_TILES_DILATE_MINMAX: + return "eevee_depth_of_field_tiles_dilate_minmax"; + case DOF_TILES_FLATTEN: + return "eevee_depth_of_field_tiles_flatten"; /* To avoid compiler warning about missing case. */ case MAX_SHADER_TYPE: return ""; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index 280aaab4e1c..dd6b9c9d4ab 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -29,6 +29,29 @@ enum eShaderType { FILM_FRAG = 0, FILM_COMP, + DOF_BOKEH_LUT, + DOF_DOWNSAMPLE, + DOF_FILTER, + DOF_GATHER_BACKGROUND_LUT, + DOF_GATHER_BACKGROUND, + DOF_GATHER_FOREGROUND_LUT, + DOF_GATHER_FOREGROUND, + DOF_GATHER_HOLE_FILL, + DOF_REDUCE, + DOF_RESOLVE_LUT, + DOF_RESOLVE, + DOF_SCATTER, + DOF_SETUP, + DOF_STABILIZE, + DOF_TILES_DILATE_MINABS, + DOF_TILES_DILATE_MINMAX, + DOF_TILES_FLATTEN, + + MOTION_BLUR_GATHER, + MOTION_BLUR_TILE_DILATE, + MOTION_BLUR_TILE_FLATTEN_RENDER, + MOTION_BLUR_TILE_FLATTEN_VIEWPORT, + MAX_SHADER_TYPE, }; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 3c10f633740..fe36cb1a17c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -23,6 +23,9 @@ using draw::SwapChain; using draw::Texture; using draw::TextureFromPool; +constexpr eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT; +constexpr eGPUSamplerState with_filter = GPU_SAMPLER_FILTER; + #endif #define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14 @@ -124,7 +127,7 @@ struct CameraData { float clip_far; eCameraType type; - bool initialized; + bool1 initialized; #ifdef __cplusplus /* Small constructor to allow detecting new buffers. */ @@ -312,6 +315,151 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Motion Blur + * \{ */ + +#define MOTION_BLUR_TILE_SIZE 32 +#define MOTION_BLUR_MAX_TILE 512 /* 16384 / MOTION_BLUR_TILE_SIZE */ +struct MotionBlurData { + /** As the name suggests. Used to avoid a division in the sampling. */ + float2 target_size_inv; + /** Viewport motion scaling factor. Make blur relative to frame time not render time. */ + float2 motion_scale; + /** Depth scaling factor. Avoid blurring background behind moving objects. */ + float depth_scale; + + float _pad0, _pad1, _pad2; +}; +BLI_STATIC_ASSERT_ALIGN(MotionBlurData, 16) + +/* For some reasons some GLSL compilers do not like this struct. + * So we declare it as a uint array instead and do indexing ourselves. */ +#ifdef __cplusplus +struct MotionBlurTileIndirection { + /** + * Stores indirection to the tile with the highest velocity covering each tile. + * This is stored using velocity in the MSB to be able to use atomicMax operations. + */ + uint prev[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE]; + uint next[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE]; +}; +BLI_STATIC_ASSERT_ALIGN(MotionBlurTileIndirection, 16) +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Depth of field + * \{ */ + +/* 5% error threshold. */ +#define DOF_FAST_GATHER_COC_ERROR 0.05 +#define DOF_GATHER_RING_COUNT 5 +#define DOF_DILATE_RING_COUNT 3 + +struct DepthOfFieldData { + /** Size of the render targets for gather & scatter passes. */ + int2 extent; + /** Size of a pixel in uv space (1.0 / extent). */ + float2 texel_size; + /** Scale factor for anisotropic bokeh. */ + float2 bokeh_anisotropic_scale; + float2 bokeh_anisotropic_scale_inv; + /* Correction factor to align main target pixels with the filtered mipmap chain texture. */ + float2 gather_uv_fac; + /** Scatter parameters. */ + float scatter_coc_threshold; + float scatter_color_threshold; + float scatter_neighbor_max_color; + int scatter_sprite_per_row; + /** Number of side the bokeh shape has. */ + float bokeh_blades; + /** Rotation of the bokeh shape. */ + float bokeh_rotation; + /** Multiplier and bias to apply to linear depth to Circle of confusion (CoC). */ + float coc_mul, coc_bias; + /** Maximum absolute allowed Circle of confusion (CoC). Min of computed max and user max. */ + float coc_abs_max; + /** Copy of camera type. */ + eCameraType camera_type; + /** Weights of spatial filtering in stabilize pass. Not array to avoid alignment restriction. */ + float4 filter_samples_weight; + float filter_center_weight; + /** Max number of sprite in the scatter pass for each ground. */ + int scatter_max_rect; + + int _pad0, _pad1; +}; +BLI_STATIC_ASSERT_ALIGN(DepthOfFieldData, 16) + +struct ScatterRect { + /** Color and CoC of the 4 pixels the scatter sprite represents. */ + float4 color_and_coc[4]; + /** Rect center position in half pixel space. */ + float2 offset; + /** Rect half extent in half pixel space. */ + float2 half_extent; +}; +BLI_STATIC_ASSERT_ALIGN(ScatterRect, 16) + +/** WORKAROUND(@fclem): This is because this file is included before common_math_lib.glsl. */ +#ifndef M_PI +# define EEVEE_PI +# define M_PI 3.14159265358979323846 /* pi */ +#endif + +static inline float coc_radius_from_camera_depth(DepthOfFieldData dof, float depth) +{ + depth = (dof.camera_type != CAMERA_ORTHO) ? 1.0f / depth : depth; + return dof.coc_mul * depth + dof.coc_bias; +} + +static inline float regular_polygon_side_length(float sides_count) +{ + return 2.0f * sinf(M_PI / sides_count); +} + +/* Returns intersection ratio between the radius edge at theta and the regular polygon edge. + * Start first corners at theta == 0. */ +static inline float circle_to_polygon_radius(float sides_count, float theta) +{ + /* From Graphics Gems from CryENGINE 3 (Siggraph 2013) by Tiago Sousa (slide + * 36). */ + float side_angle = (2.0f * M_PI) / sides_count; + return cosf(side_angle * 0.5f) / + cosf(theta - side_angle * floorf((sides_count * theta + M_PI) / (2.0f * M_PI))); +} + +/* Remap input angle to have homogenous spacing of points along a polygon edge. + * Expects theta to be in [0..2pi] range. */ +static inline float circle_to_polygon_angle(float sides_count, float theta) +{ + float side_angle = (2.0f * M_PI) / sides_count; + float halfside_angle = side_angle * 0.5f; + float side = floorf(theta / side_angle); + /* Length of segment from center to the middle of polygon side. */ + float adjacent = circle_to_polygon_radius(sides_count, 0.0f); + + /* This is the relative position of the sample on the polygon half side. */ + float local_theta = theta - side * side_angle; + float ratio = (local_theta - halfside_angle) / halfside_angle; + + float halfside_len = regular_polygon_side_length(sides_count) * 0.5f; + float opposite = ratio * halfside_len; + + /* NOTE: atan(y_over_x) has output range [-M_PI_2..M_PI_2]. */ + float final_local_theta = atanf(opposite / adjacent); + + return side * side_angle + final_local_theta; +} + +#ifdef EEVEE_PI +# undef M_PI +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Ray-Tracing * \{ */ @@ -370,7 +518,12 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer) using AOVsInfoDataBuf = draw::StorageBuffer<AOVsInfoData>; using CameraDataBuf = draw::UniformBuffer<CameraData>; +using DepthOfFieldDataBuf = draw::UniformBuffer<DepthOfFieldData>; +using DepthOfFieldScatterListBuf = draw::StorageArrayBuffer<ScatterRect, 16, true>; +using DrawIndirectBuf = draw::StorageBuffer<DrawCommand, true>; using FilmDataBuf = draw::UniformBuffer<FilmData>; +using MotionBlurDataBuf = draw::UniformBuffer<MotionBlurData>; +using MotionBlurTileIndirectionBuf = draw::StorageBuffer<MotionBlurTileIndirection, true>; using SamplingDataBuf = draw::StorageBuffer<SamplingData>; using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>; using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>; diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index 048daf1b2db..36734f0c28c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -32,13 +32,16 @@ namespace blender::eevee { void VelocityModule::init() { - if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR)) { - /* No motion blur and the vector pass was requested. Do the step sync here. */ + if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) != 0) { + /* No motion blur and the vector pass was requested. Do the steps sync here. */ const Scene *scene = inst_.scene; float initial_time = scene->r.cfra + scene->r.subframe; step_sync(STEP_PREVIOUS, initial_time - 1.0f); step_sync(STEP_NEXT, initial_time + 1.0f); + inst_.set_time(initial_time); + step_ = STEP_CURRENT; + /* Let the main sync loop handle the current step. */ } } @@ -64,10 +67,12 @@ void VelocityModule::step_camera_sync() { inst_.camera.sync(); *camera_steps[step_] = inst_.camera.data_get(); + step_time[step_] = inst_.scene->r.cfra + inst_.scene->r.subframe; /* Fix undefined camera steps when rendering is starting. */ if ((step_ == STEP_CURRENT) && (camera_steps[STEP_PREVIOUS]->initialized == false)) { *camera_steps[STEP_PREVIOUS] = *static_cast<CameraData *>(camera_steps[step_]); camera_steps[STEP_PREVIOUS]->initialized = true; + step_time[STEP_PREVIOUS] = step_time[step_]; } } @@ -212,6 +217,7 @@ void VelocityModule::step_swap() SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]); SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]); SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]); + SWAP(float, step_time[step_a], step_time[step_b]); for (VelocityObjectData &vel : velocity_map.values()) { vel.obj.ofs[step_a] = vel.obj.ofs[step_b]; @@ -238,10 +244,7 @@ void VelocityModule::step_swap() void VelocityModule::begin_sync() { - if (inst_.is_viewport()) { - /* Viewport always evaluate current step. */ - step_ = STEP_CURRENT; - } + step_ = STEP_CURRENT; step_camera_sync(); object_steps_usage[step_] = 0; } @@ -360,6 +363,21 @@ bool VelocityModule::camera_has_motion() const *camera_steps[STEP_NEXT] != *camera_steps[STEP_CURRENT]; } +bool VelocityModule::camera_changed_projection() const +{ + /* Only valid after sync. */ + if (inst_.is_viewport()) { + return camera_steps[STEP_PREVIOUS]->type != camera_steps[STEP_CURRENT]->type; + } + /* Cannot happen in render mode since we set the type during the init phase. */ + return false; +} + +float VelocityModule::step_time_delta_get(eVelocityStep start, eVelocityStep end) const +{ + return step_time[end] - step_time[start]; +} + /** \} */ } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh index 826cd631a96..01b8a5fb8c1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh @@ -56,6 +56,8 @@ class VelocityModule { int3 object_steps_usage = int3(0); /** Buffer of all #VelocityIndex used in this frame. Indexed by draw manager resource id. */ VelocityIndexBuf indirection_buf; + /** Frame time at which each steps were evaluated. */ + float3 step_time; /** * Copies of camera data. One for previous and one for next time step. @@ -78,7 +80,6 @@ class VelocityModule { } for (CameraDataBuf *&step_buf : camera_steps) { step_buf = new CameraDataBuf(); - /* */ } }; @@ -112,6 +113,10 @@ class VelocityModule { void bind_resources(DRWShadingGroup *grp); bool camera_has_motion() const; + bool camera_changed_projection() const; + + /* Returns frame time difference between two steps. */ + float step_time_delta_get(eVelocityStep start, eVelocityStep end) const; private: bool object_has_velocity(const Object *ob); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index 55741bee4df..c195f68380c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -79,14 +79,11 @@ void ShadingView::sync() render_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p); // dof_.sync(winmat_p, extent_); - // mb_.sync(extent_); // rt_buffer_opaque_.sync(extent_); // rt_buffer_refract_.sync(extent_); // inst_.hiz_back.view_sync(extent_); // inst_.hiz_front.view_sync(extent_); // inst_.gbuffer.view_sync(extent_); - - postfx_tx_.sync(); } void ShadingView::render() @@ -96,12 +93,8 @@ void ShadingView::render() } /* Query temp textures and create frame-buffers. */ - /* HACK: View name should be unique and static. - * With this, we can reuse the same texture across views. */ - DrawEngineType *owner = (DrawEngineType *)name_; - RenderBuffers &rbufs = inst_.render_buffers; - rbufs.acquire(extent_, owner); + rbufs.acquire(extent_); combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx), GPU_ATTACHMENT_TEXTURE(rbufs.combined_tx)); prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx), @@ -138,9 +131,9 @@ void ShadingView::render() // inst_.lights.debug_draw(view_fb_); // inst_.shadows.debug_draw(view_fb_); - // GPUTexture *final_radiance_tx = render_post(combined_tx_); + GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx); - inst_.film.accumulate(sub_view_); + inst_.film.accumulate(sub_view_, combined_final_tx); rbufs.release(); postfx_tx_.release(); @@ -148,23 +141,19 @@ void ShadingView::render() DRW_stats_group_end(); } -GPUTexture *ShadingView::render_post(GPUTexture *input_tx) +GPUTexture *ShadingView::render_postfx(GPUTexture *input_tx) { -#if 0 - if (!dof_.postfx_enabled() && !mb_.enabled()) { + if (!inst_.depth_of_field.postfx_enabled() && !inst_.motion_blur.postfx_enabled()) { return input_tx; } - /* HACK: View name should be unique and static. - * With this, we can reuse the same texture across views. */ - postfx_tx_.acquire(extent_, GPU_RGBA16F, (void *)name_); + postfx_tx_.acquire(extent_, GPU_RGBA16F); - GPUTexture *velocity_tx = velocity_.view_vectors_get(); GPUTexture *output_tx = postfx_tx_; /* Swapping is done internally. Actual output is set to the next input. */ - dof_.render(depth_tx_, &input_tx, &output_tx); - mb_.render(depth_tx_, velocity_tx, &input_tx, &output_tx); -#endif + inst_.depth_of_field.render(&input_tx, &output_tx, dof_buffer_); + inst_.motion_blur.render(&input_tx, &output_tx); + return input_tx; } @@ -189,7 +178,7 @@ void ShadingView::update_view() /* FIXME(fclem): The offset may be is noticeably large and the culling might make object pop * out of the blurring radius. To fix this, use custom enlarged culling matrix. */ - // dof_.jitter_apply(winmat, viewmat); + inst_.depth_of_field.jitter_apply(winmat, viewmat); DRW_view_update_sub(render_view_, viewmat.ptr(), winmat.ptr()); // inst_.lightprobes.set_view(render_view_, extent_); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index c6faebdd0e5..65f27aba795 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -41,13 +41,10 @@ class ShadingView { /** Matrix to apply to the viewmat. */ const float (*face_matrix_)[4]; - /** Post-FX modules. */ - // DepthOfField dof_; - // MotionBlur mb_; - /** Raytracing persistent buffers. Only opaque and refraction can have surface tracing. */ // RaytraceBuffer rt_buffer_opaque_; // RaytraceBuffer rt_buffer_refract_; + DepthOfFieldBuffer dof_buffer_; Framebuffer prepass_fb_; Framebuffer combined_fb_; @@ -78,7 +75,7 @@ class ShadingView { void render(); - GPUTexture *render_post(GPUTexture *input_tx); + GPUTexture *render_postfx(GPUTexture *input_tx); private: void update_view(); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_colorspace_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_colorspace_lib.glsl new file mode 100644 index 00000000000..d5fdaae6fc1 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_colorspace_lib.glsl @@ -0,0 +1,37 @@ + +/* -------------------------------------------------------------------- */ +/** \name YCoCg + * \{ */ + +vec3 colorspace_YCoCg_from_scene_linear(vec3 rgb_color) +{ + const mat3 colorspace_tx = transpose(mat3(vec3(1, 2, 1), /* Y */ + vec3(2, 0, -2), /* Co */ + vec3(-1, 2, -1))); /* Cg */ + return colorspace_tx * rgb_color; +} + +vec4 colorspace_YCoCg_from_scene_linear(vec4 rgba_color) +{ + return vec4(colorspace_YCoCg_from_scene_linear(rgba_color.rgb), rgba_color.a); +} + +vec3 colorspace_scene_linear_from_YCoCg(vec3 ycocg_color) +{ + float Y = ycocg_color.x; + float Co = ycocg_color.y; + float Cg = ycocg_color.z; + + vec3 rgb_color; + rgb_color.r = Y + Co - Cg; + rgb_color.g = Y + Cg; + rgb_color.b = Y - Co - Cg; + return rgb_color * 0.25; +} + +vec4 colorspace_scene_linear_from_YCoCg(vec4 ycocg_color) +{ + return vec4(colorspace_scene_linear_from_YCoCg(ycocg_color.rgb), ycocg_color.a); +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl new file mode 100644 index 00000000000..57f229feedb --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl @@ -0,0 +1,680 @@ + +/** + * Depth of Field Gather accumulator. + * We currently have only 2 which are very similar. + * One is for the halfres gather passes and the other one for slight in focus regions. + **/ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Options. + * \{ */ + +/* Quality options */ +#ifdef DOF_HOLEFILL_PASS +/* No need for very high density for hole_fill. */ +const int gather_ring_count = 3; +const int gather_ring_density = 3; +const int gather_max_density_change = 0; +const int gather_density_change_ring = 1; +#else +const int gather_ring_count = DOF_GATHER_RING_COUNT; +const int gather_ring_density = 3; +const int gather_max_density_change = 50; /* Dictates the maximum good quality blur. */ +const int gather_density_change_ring = 1; +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Constants. + * \{ */ + +const float unit_ring_radius = 1.0 / float(gather_ring_count); +const float unit_sample_radius = 1.0 / float(gather_ring_count + 0.5); +const float large_kernel_radius = 0.5 + float(gather_ring_count); +const float smaller_kernel_radius = 0.5 + float(gather_ring_count - gather_density_change_ring); +/* NOTE(fclem) the bias is reducing issues with density change visible transition. */ +const float radius_downscale_factor = smaller_kernel_radius / large_kernel_radius; +const int change_density_at_ring = (gather_ring_count - gather_density_change_ring + 1); +const float coc_radius_error = 2.0; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Gather common. + * \{ */ + +struct DofGatherData { + vec4 color; + float weight; + float dist; /* TODO remove */ + /* For scatter occlusion. */ + float coc; + float coc_sqr; + /* For ring bucket merging. */ + float transparency; + + float layer_opacity; +}; + +#define GATHER_DATA_INIT DofGatherData(vec4(0.0), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + +/* Intersection with the center of the kernel. */ +float dof_intersection_weight(float coc, float distance_from_center, float intersection_multiplier) +{ + if (no_smooth_intersection) { + return step(0.0, (abs(coc) - distance_from_center)); + } + else { + /* (Slide 64). */ + return saturate((abs(coc) - distance_from_center) * intersection_multiplier + 0.5); + } +} + +/* Returns weight of the sample for the outer bucket (containing previous + * rings). */ +float dof_gather_accum_weight(float coc, float bordering_radius, bool first_ring) +{ + /* First ring has nothing to be mixed against. */ + if (first_ring) { + return 0.0; + } + return saturate(coc - bordering_radius); +} + +void dof_gather_ammend_weight(inout DofGatherData sample_data, float weight) +{ + sample_data.color *= weight; + sample_data.coc *= weight; + sample_data.coc_sqr *= weight; + sample_data.weight *= weight; +} + +void dof_gather_accumulate_sample(DofGatherData sample_data, + float weight, + inout DofGatherData accum_data) +{ + accum_data.color += sample_data.color * weight; + accum_data.coc += sample_data.coc * weight; + accum_data.coc_sqr += sample_data.coc * (sample_data.coc * weight); + accum_data.weight += weight; +} + +void dof_gather_accumulate_sample_pair(DofGatherData pair_data[2], + float bordering_radius, + float intersection_multiplier, + bool first_ring, + const bool do_fast_gather, + const bool is_foreground, + inout DofGatherData ring_data, + inout DofGatherData accum_data) +{ + if (do_fast_gather) { + for (int i = 0; i < 2; i++) { + dof_gather_accumulate_sample(pair_data[i], 1.0, accum_data); + accum_data.layer_opacity += 1.0; + } + return; + } + +#if 0 + const float mirroring_threshold = -dof_layer_threshold - dof_layer_offset; + /* TODO(fclem) Promote to parameter? dither with Noise? */ + const float mirroring_min_distance = 15.0; + if (pair_data[0].coc < mirroring_threshold && + (pair_data[1].coc - mirroring_min_distance) > pair_data[0].coc) { + pair_data[1].coc = pair_data[0].coc; + } + else if (pair_data[1].coc < mirroring_threshold && + (pair_data[0].coc - mirroring_min_distance) > pair_data[1].coc) { + pair_data[0].coc = pair_data[1].coc; + } +#endif + + for (int i = 0; i < 2; i++) { + float sample_weight = dof_sample_weight(pair_data[i].coc); + float layer_weight = dof_layer_weight(pair_data[i].coc, is_foreground); + float inter_weight = dof_intersection_weight( + pair_data[i].coc, pair_data[i].dist, intersection_multiplier); + float weight = inter_weight * layer_weight * sample_weight; + + /** + * If a CoC is larger than bordering radius we accumulate it to the general accumulator. + * If not, we accumulate to the ring bucket. This is to have more consistent sample occlusion. + **/ + float accum_weight = dof_gather_accum_weight(pair_data[i].coc, bordering_radius, first_ring); + dof_gather_accumulate_sample(pair_data[i], weight * accum_weight, accum_data); + dof_gather_accumulate_sample(pair_data[i], weight * (1.0 - accum_weight), ring_data); + + accum_data.layer_opacity += layer_weight; + + if (is_foreground) { + ring_data.transparency += 1.0 - inter_weight * layer_weight; + } + else { + float coc = is_foreground ? -pair_data[i].coc : pair_data[i].coc; + ring_data.transparency += saturate(coc - bordering_radius); + } + } +} + +void dof_gather_accumulate_sample_ring(DofGatherData ring_data, + int sample_count, + bool first_ring, + const bool do_fast_gather, + /* accum_data occludes the ring_data if true. */ + const bool reversed_occlusion, + inout DofGatherData accum_data) +{ + if (do_fast_gather) { + /* Do nothing as ring_data contains nothing. All samples are already in + * accum_data. */ + return; + } + + if (first_ring) { + /* Layer opacity is directly accumulated into accum_data data. */ + accum_data.color = ring_data.color; + accum_data.coc = ring_data.coc; + accum_data.coc_sqr = ring_data.coc_sqr; + accum_data.weight = ring_data.weight; + + accum_data.transparency = ring_data.transparency / float(sample_count); + return; + } + + if (ring_data.weight == 0.0) { + return; + } + + float ring_avg_coc = ring_data.coc / ring_data.weight; + float accum_avg_coc = accum_data.coc / accum_data.weight; + + /* Smooth test to set opacity to see if the ring average coc occludes the + * accumulation. Test is reversed to be multiplied against opacity. */ + float ring_occlu = saturate(accum_avg_coc - ring_avg_coc); + /* The bias here is arbitrary. Seems to avoid weird looking foreground in most + * cases. We might need to make it a parameter or find a relative bias. */ + float accum_occlu = saturate((ring_avg_coc - accum_avg_coc) * 0.1 - 1.0); + + if (is_resolve) { + ring_occlu = accum_occlu = 0.0; + } + + if (no_gather_occlusion) { + ring_occlu = 0.0; + accum_occlu = 0.0; + } + + /* (Slide 40) */ + float ring_opacity = saturate(1.0 - ring_data.transparency / float(sample_count)); + float accum_opacity = 1.0 - accum_data.transparency; + + if (reversed_occlusion) { + /* Accum_data occludes the ring. */ + float alpha = (accum_data.weight == 0.0) ? 0.0 : accum_opacity * accum_occlu; + float one_minus_alpha = 1.0 - alpha; + + accum_data.color += ring_data.color * one_minus_alpha; + accum_data.coc += ring_data.coc * one_minus_alpha; + accum_data.coc_sqr += ring_data.coc_sqr * one_minus_alpha; + accum_data.weight += ring_data.weight * one_minus_alpha; + + accum_data.transparency *= 1.0 - ring_opacity; + } + else { + /* Ring occludes the accum_data (Same as reference). */ + float alpha = (accum_data.weight == 0.0) ? 1.0 : (ring_opacity * ring_occlu); + float one_minus_alpha = 1.0 - alpha; + + accum_data.color = accum_data.color * one_minus_alpha + ring_data.color; + accum_data.coc = accum_data.coc * one_minus_alpha + ring_data.coc; + accum_data.coc_sqr = accum_data.coc_sqr * one_minus_alpha + ring_data.coc_sqr; + accum_data.weight = accum_data.weight * one_minus_alpha + ring_data.weight; + } +} + +/* FIXME(fclem) Seems to be wrong since it needs ringcount+1 as input for + * slightfocus gather. */ +/* This should be replaced by web_sample_count_get() but doing so is breaking other things. */ +int dof_gather_total_sample_count(const int ring_count, const int ring_density) +{ + return (ring_count * ring_count - ring_count) * ring_density + 1; +} + +void dof_gather_accumulate_center_sample(DofGatherData center_data, + float bordering_radius, + int i_radius, + const bool do_fast_gather, + const bool is_foreground, + const bool is_resolve, + inout DofGatherData accum_data) +{ + float layer_weight = dof_layer_weight(center_data.coc, is_foreground); + float sample_weight = dof_sample_weight(center_data.coc); + float weight = layer_weight * sample_weight; + float accum_weight = dof_gather_accum_weight(center_data.coc, bordering_radius, false); + + if (do_fast_gather) { + /* Hope for the compiler to optimize the above. */ + layer_weight = 1.0; + sample_weight = 1.0; + accum_weight = 1.0; + weight = 1.0; + } + + center_data.transparency = 1.0 - weight; + + dof_gather_accumulate_sample(center_data, weight * accum_weight, accum_data); + + if (!do_fast_gather) { + if (is_resolve) { + /* NOTE(fclem): Hack to smooth transition to full in-focus opacity. */ + int total_sample_count = dof_gather_total_sample_count(i_radius + 1, + DOF_SLIGHT_FOCUS_DENSITY); + float fac = saturate(1.0 - abs(center_data.coc) / float(dof_layer_threshold)); + accum_data.layer_opacity += float(total_sample_count) * fac * fac; + } + accum_data.layer_opacity += layer_weight; + + /* Logic of dof_gather_accumulate_sample(). */ + weight *= (1.0 - accum_weight); + center_data.coc_sqr = center_data.coc * (center_data.coc * weight); + center_data.color *= weight; + center_data.coc *= weight; + center_data.weight = weight; + + if (is_foreground && !is_resolve) { + /* Reduce issue with closer foreground over distant foreground. */ + float ring_area = sqr(bordering_radius); + dof_gather_ammend_weight(center_data, ring_area); + } + + /* Accumulate center as its own ring. */ + dof_gather_accumulate_sample_ring( + center_data, 1, false, do_fast_gather, is_foreground, accum_data); + } +} + +int dof_gather_total_sample_count_with_density_change(const int ring_count, + const int ring_density, + int density_change) +{ + int sample_count_per_density_change = dof_gather_total_sample_count(ring_count, ring_density) - + dof_gather_total_sample_count( + ring_count - gather_density_change_ring, ring_density); + + return dof_gather_total_sample_count(ring_count, ring_density) + + sample_count_per_density_change * density_change; +} + +void dof_gather_accumulate_resolve(int total_sample_count, + DofGatherData accum_data, + out vec4 out_col, + out float out_weight, + out vec2 out_occlusion) +{ + float weight_inv = safe_rcp(accum_data.weight); + out_col = accum_data.color * weight_inv; + out_occlusion = vec2(abs(accum_data.coc), accum_data.coc_sqr) * weight_inv; + + if (is_foreground) { + out_weight = 1.0 - accum_data.transparency; + } + else if (accum_data.weight > 0.0) { + out_weight = accum_data.layer_opacity / float(total_sample_count); + } + else { + out_weight = 0.0; + } + /* Gathering may not accumulate to 1.0 alpha because of float precision. */ + if (out_weight > 0.99) { + out_weight = 1.0; + } + else if (out_weight < 0.01) { + out_weight = 0.0; + } + /* Same thing for alpha channel. */ + if (out_col.a > 0.993) { + out_col.a = 1.0; + } + else if (out_col.a < 0.003) { + out_col.a = 0.0; + } +} + +float dof_load_gather_coc(sampler2D gather_input_coc_tx, vec2 uv, float lod) +{ + float coc = textureLod(gather_input_coc_tx, uv, lod).r; + /* We gather at halfres. CoC must be divided by 2 to be compared against radii. */ + return coc * 0.5; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Common Gather accumulator. + * \{ */ + +/* Radii needs to be halfres CoC sizes. */ +bool dof_do_density_change(float base_radius, float min_intersectable_radius) +{ + /* Reduce artifact for very large blur. */ + min_intersectable_radius *= 0.1; + + bool need_new_density = (base_radius * unit_ring_radius > min_intersectable_radius); + bool larger_than_min_density = (base_radius * radius_downscale_factor > + float(gather_ring_count)); + + return need_new_density && larger_than_min_density; +} + +void dof_gather_init(float base_radius, + vec2 noise, + out vec2 center_co, + out float lod, + out float intersection_multiplier) +{ + /* Jitter center half a ring to reduce undersampling. */ + vec2 jitter_ofs = 0.499 * sample_disk(noise); + if (DOF_BOKEH_TEXTURE) { + jitter_ofs *= dof_buf.bokeh_anisotropic_scale; + } + vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; + center_co = frag_coord + jitter_ofs * base_radius * unit_sample_radius; + + /* TODO(fclem) Seems like the default lod selection is too big. Bias to avoid blocky moving out + * of focus shapes. */ + const float lod_bias = -2.0; + lod = max(floor(log2(base_radius * unit_sample_radius) + 0.5) + lod_bias, 0.0); + + if (no_gather_mipmaps) { + lod = 0.0; + } + /* (Slide 64). */ + intersection_multiplier = pow(0.5, lod); +} + +void dof_gather_accumulator(sampler2D color_tx, + sampler2D color_bilinear_tx, + sampler2D coc_tx, + sampler2D bkh_lut_tx, /* Renamed because of ugly macro. */ + float base_radius, + float min_intersectable_radius, + const bool do_fast_gather, + const bool do_density_change, + out vec4 out_color, + out float out_weight, + out vec2 out_occlusion) +{ + vec2 frag_coord = vec2(gl_GlobalInvocationID.xy); + vec2 noise_offset = sampling_rng_2D_get(SAMPLING_LENS_U); + vec2 noise = no_gather_random ? vec2(0.0, 0.0) : + vec2(interlieved_gradient_noise(frag_coord, 0, noise_offset.x), + interlieved_gradient_noise(frag_coord, 1, noise_offset.y)); + + if (!do_fast_gather) { + /* Jitter the radius to reduce noticeable density changes. */ + base_radius += noise.x * unit_ring_radius * base_radius; + } + else { + /* Jittering the radius more than we need means we are going to feather the bokeh shape half a + * ring. So we need to compensate for fast gather that does not check CoC intersection. */ + base_radius += (0.5 - noise.x) * 1.5 * unit_ring_radius * base_radius; + } + /* TODO(fclem) another seed? For now Cranly-Partterson rotation with golden ratio. */ + noise.x = fract(noise.x * 6.1803398875); + + float lod, isect_mul; + vec2 center_co; + dof_gather_init(base_radius, noise, center_co, lod, isect_mul); + + bool first_ring = true; + + DofGatherData accum_data = GATHER_DATA_INIT; + + int density_change = 0; + for (int ring = gather_ring_count; ring > 0; ring--) { + int sample_pair_count = gather_ring_density * ring; + + float step_rot = M_PI / float(sample_pair_count); + mat2 step_rot_mat = rot2_from_angle(step_rot); + + float angle_offset = noise.y * step_rot; + vec2 offset = vec2(cos(angle_offset), sin(angle_offset)); + + float ring_radius = float(ring) * unit_sample_radius * base_radius; + + /* Slide 38. */ + float bordering_radius = ring_radius + + (0.5 + coc_radius_error) * base_radius * unit_sample_radius; + DofGatherData ring_data = GATHER_DATA_INIT; + for (int sample_pair = 0; sample_pair < sample_pair_count; sample_pair++) { + offset = step_rot_mat * offset; + + DofGatherData pair_data[2]; + for (int i = 0; i < 2; i++) { + vec2 offset_co = ((i == 0) ? offset : -offset); + if (DOF_BOKEH_TEXTURE) { + /* Scaling to 0.25 for speed. Improves texture cache hit. */ + offset_co = texture(bkh_lut_tx, offset_co * 0.25 + 0.5).rg; + offset_co *= (is_foreground) ? -dof_buf.bokeh_anisotropic_scale : + dof_buf.bokeh_anisotropic_scale; + } + vec2 sample_co = center_co + offset_co * ring_radius; + vec2 sample_uv = sample_co * dof_buf.gather_uv_fac; + if (do_fast_gather) { + pair_data[i].color = textureLod(color_bilinear_tx, sample_uv, lod); + } + else { + pair_data[i].color = textureLod(color_tx, sample_uv, lod); + } + pair_data[i].coc = dof_load_gather_coc(coc_tx, sample_uv, lod); + pair_data[i].dist = ring_radius; + } + + dof_gather_accumulate_sample_pair(pair_data, + bordering_radius, + isect_mul, + first_ring, + do_fast_gather, + is_foreground, + ring_data, + accum_data); + } + + if (is_foreground) { + /* Reduce issue with closer foreground over distant foreground. */ + /* TODO(fclem) this seems to not be completely correct as the issue remains. */ + float ring_area = (sqr(float(ring) + 0.5 + coc_radius_error) - + sqr(float(ring) - 0.5 + coc_radius_error)) * + sqr(base_radius * unit_sample_radius); + dof_gather_ammend_weight(ring_data, ring_area); + } + + dof_gather_accumulate_sample_ring( + ring_data, sample_pair_count * 2, first_ring, do_fast_gather, is_foreground, accum_data); + + first_ring = false; + + if (do_density_change && (ring == change_density_at_ring) && + (density_change < gather_max_density_change)) { + if (dof_do_density_change(base_radius, min_intersectable_radius)) { + base_radius *= radius_downscale_factor; + ring += gather_density_change_ring; + /* We need to account for the density change in the weights (slide 62). + * For that multiply old kernel data by its area divided by the new kernel area. */ + const float outer_rings_weight = 1.0 / (radius_downscale_factor * radius_downscale_factor); + /* Samples are already weighted per ring in foreground pass. */ + if (!is_foreground) { + dof_gather_ammend_weight(accum_data, outer_rings_weight); + } + /* Re-init kernel position & sampling parameters. */ + dof_gather_init(base_radius, noise, center_co, lod, isect_mul); + density_change++; + } + } + } + + { + /* Center sample. */ + vec2 sample_uv = center_co * dof_buf.gather_uv_fac; + DofGatherData center_data; + if (do_fast_gather) { + center_data.color = textureLod(color_bilinear_tx, sample_uv, lod); + } + else { + center_data.color = textureLod(color_tx, sample_uv, lod); + } + center_data.coc = dof_load_gather_coc(coc_tx, sample_uv, lod); + center_data.dist = 0.0; + + /* Slide 38. */ + float bordering_radius = (0.5 + coc_radius_error) * base_radius * unit_sample_radius; + + dof_gather_accumulate_center_sample( + center_data, bordering_radius, 0, do_fast_gather, is_foreground, false, accum_data); + } + + int total_sample_count = dof_gather_total_sample_count_with_density_change( + gather_ring_count, gather_ring_density, density_change); + dof_gather_accumulate_resolve( + total_sample_count, accum_data, out_color, out_weight, out_occlusion); + + if (debug_gather_perf && density_change > 0) { + float fac = saturate(float(density_change) / float(10.0)); + out_color.rgb = avg(out_color.rgb) * neon_gradient(fac); + } + if (debug_gather_perf && do_fast_gather) { + out_color.rgb = avg(out_color.rgb) * vec3(0.0, 1.0, 0.0); + } + if (debug_scatter_perf) { + out_color.rgb = avg(out_color.rgb) * vec3(0.0, 1.0, 0.0); + } + + /* Output premultiplied color so we can use bilinear sampler in resolve pass. */ + out_color *= out_weight; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Slight focus accumulator. + * + * The full pixel neighborhood is gathered. + * \{ */ + +void dof_slight_focus_gather(sampler2D depth_tx, + sampler2D color_tx, + sampler2D bkh_lut_tx, /* Renamed because of ugly macro job. */ + float radius, + out vec4 out_color, + out float out_weight, + out float out_center_coc) +{ + vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; + vec2 noise_offset = sampling_rng_2D_get(SAMPLING_LENS_U); + vec2 noise = no_gather_random ? vec2(0.0) : + vec2(interlieved_gradient_noise(frag_coord, 3, noise_offset.x), + interlieved_gradient_noise(frag_coord, 5, noise_offset.y)); + + DofGatherData fg_accum = GATHER_DATA_INIT; + DofGatherData bg_accum = GATHER_DATA_INIT; + + int i_radius = clamp(int(radius), 0, int(dof_layer_threshold)); + + const float sample_count_max = float(DOF_SLIGHT_FOCUS_SAMPLE_MAX); + /* Scale by search area. */ + float sample_count = sample_count_max * saturate(sqr(radius) / sqr(dof_layer_threshold)); + + bool first_ring = true; + + for (float s = 0.0; s < sample_count; s++) { + vec2 rand2 = fract(hammersley_2d(s, sample_count) + noise); + vec2 offset = sample_disk(rand2); + float ring_dist = sqrt(rand2.y); + + DofGatherData pair_data[2]; + for (int i = 0; i < 2; i++) { + vec2 sample_offset = ((i == 0) ? offset : -offset); + /* OPTI: could precompute the factor. */ + vec2 sample_uv = (frag_coord + sample_offset) / vec2(textureSize(depth_tx, 0)); + float depth = textureLod(depth_tx, sample_uv, 0.0).r; + pair_data[i].coc = dof_coc_from_depth(dof_buf, sample_uv, depth); + pair_data[i].color = safe_color(textureLod(color_tx, sample_uv, 0.0)); + pair_data[i].dist = ring_dist; + if (DOF_BOKEH_TEXTURE) { + /* Contains subpixel distance to bokeh shape. */ + ivec2 lut_texel = ivec2(round(sample_offset)) + dof_max_slight_focus_radius; + pair_data[i].dist = texelFetch(bkh_lut_tx, lut_texel, 0).r; + } + pair_data[i].coc = clamp(pair_data[i].coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max); + } + + float bordering_radius = ring_dist + 0.5; + const float isect_mul = 1.0; + DofGatherData bg_ring = GATHER_DATA_INIT; + dof_gather_accumulate_sample_pair( + pair_data, bordering_radius, isect_mul, first_ring, false, false, bg_ring, bg_accum); + /* Treat each sample as a ring. */ + dof_gather_accumulate_sample_ring(bg_ring, 2, first_ring, false, false, bg_accum); + + if (DOF_BOKEH_TEXTURE) { + /* Swap distances in order to flip bokeh shape for foreground. */ + float tmp = pair_data[0].dist; + pair_data[0].dist = pair_data[1].dist; + pair_data[1].dist = tmp; + } + DofGatherData fg_ring = GATHER_DATA_INIT; + dof_gather_accumulate_sample_pair( + pair_data, bordering_radius, isect_mul, first_ring, false, true, fg_ring, fg_accum); + /* Treat each sample as a ring. */ + dof_gather_accumulate_sample_ring(fg_ring, 2, first_ring, false, true, fg_accum); + + first_ring = false; + } + + /* Center sample. */ + vec2 sample_uv = frag_coord / vec2(textureSize(depth_tx, 0)); + DofGatherData center_data; + center_data.color = safe_color(textureLod(color_tx, sample_uv, 0.0)); + center_data.coc = dof_coc_from_depth(dof_buf, sample_uv, textureLod(depth_tx, sample_uv, 0.0).r); + center_data.coc = clamp(center_data.coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max); + center_data.dist = 0.0; + + out_center_coc = center_data.coc; + + /* Slide 38. */ + float bordering_radius = 0.5; + + dof_gather_accumulate_center_sample( + center_data, bordering_radius, i_radius, false, true, true, fg_accum); + dof_gather_accumulate_center_sample( + center_data, bordering_radius, i_radius, false, false, true, bg_accum); + + vec4 bg_col, fg_col; + float bg_weight, fg_weight; + vec2 unused_occlusion; + + int total_sample_count = int(sample_count) * 2 + 1; + dof_gather_accumulate_resolve(total_sample_count, bg_accum, bg_col, bg_weight, unused_occlusion); + dof_gather_accumulate_resolve(total_sample_count, fg_accum, fg_col, fg_weight, unused_occlusion); + + /* Fix weighting issues on perfectly focus to slight focus transitionning areas. */ + if (abs(center_data.coc) < 0.5) { + bg_col = center_data.color; + bg_weight = 1.0; + } + + /* Alpha Over */ + float alpha = 1.0 - fg_weight; + out_weight = bg_weight * alpha + fg_weight; + out_color = bg_col * bg_weight * alpha + fg_col * fg_weight; +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl new file mode 100644 index 00000000000..26a597b04e8 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl @@ -0,0 +1,55 @@ + +/** + * Bokeh Look Up Table: This outputs a radius multiplier to shape the sampling in gather pass or + * the scatter sprite appearance. This is only used if bokeh shape is either anamorphic or is not + * a perfect circle. + * We correct samples spacing for polygonal bokeh shapes. However, we do not for anamorphic bokeh + * as it is way more complex and expensive to do. + */ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +void main() +{ + vec2 gather_uv = ((vec2(gl_GlobalInvocationID.xy) + 0.5) / float(DOF_BOKEH_LUT_SIZE)); + /* Center uv in range [-1..1]. */ + gather_uv = gather_uv * 2.0 - 1.0; + + vec2 slight_focus_texel = vec2(gl_GlobalInvocationID.xy) - float(dof_max_slight_focus_radius); + + float radius = length(gather_uv); + + if (dof_buf.bokeh_blades > 0.0) { + /* NOTE: atan(y,x) has output range [-M_PI..M_PI], so add 2pi to avoid negative angles. */ + float theta = atan(gather_uv.y, gather_uv.x) + M_2PI; + float r = length(gather_uv); + + radius /= circle_to_polygon_radius(dof_buf.bokeh_blades, theta - dof_buf.bokeh_rotation); + + float theta_new = circle_to_polygon_angle(dof_buf.bokeh_blades, theta); + float r_new = circle_to_polygon_radius(dof_buf.bokeh_blades, theta_new); + + theta_new -= dof_buf.bokeh_rotation; + + gather_uv = r_new * vec2(-cos(theta_new), sin(theta_new)); + + { + /* Slight focus distance */ + slight_focus_texel *= dof_buf.bokeh_anisotropic_scale_inv; + float theta = atan(slight_focus_texel.y, -slight_focus_texel.x) + M_2PI; + slight_focus_texel /= circle_to_polygon_radius(dof_buf.bokeh_blades, + theta + dof_buf.bokeh_rotation); + } + } + else { + gather_uv *= safe_rcp(length(gather_uv)); + } + + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + /* For gather store the normalized UV. */ + imageStore(out_gather_lut_img, texel, gather_uv.xyxy); + /* For scatter store distance. LUT will be scaled by COC. */ + imageStore(out_scatter_lut_img, texel, vec4(radius)); + /* For slight focus gather store pixel perfect distance. */ + imageStore(out_resolve_lut_img, texel, vec4(length(slight_focus_texel))); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl new file mode 100644 index 00000000000..3d45f285da9 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl @@ -0,0 +1,32 @@ + +/** + * Downsample pass: CoC aware downsample to quarter resolution. + * + * Pretty much identical to the setup pass but get CoC from buffer. + * Also does not weight luma for the bilateral weights. + */ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +void main() +{ + vec2 halfres_texel_size = 1.0 / vec2(textureSize(color_tx, 0).xy); + /* Center uv around the 4 halfres pixels. */ + vec2 quad_center = vec2(gl_GlobalInvocationID * 2 + 1) * halfres_texel_size; + + vec4 colors[4]; + vec4 cocs; + for (int i = 0; i < 4; i++) { + vec2 sample_uv = quad_center + quad_offsets[i] * halfres_texel_size; + colors[i] = textureLod(color_tx, sample_uv, 0.0); + cocs[i] = textureLod(coc_tx, sample_uv, 0.0).r; + } + + vec4 weights = dof_bilateral_coc_weights(cocs); + /* Normalize so that the sum is 1. */ + weights *= safe_rcp(sum(weights)); + + vec4 out_color = weighted_sum_array(colors, weights); + + imageStore(out_color_img, ivec2(gl_GlobalInvocationID.xy), out_color); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl new file mode 100644 index 00000000000..c5c0e210109 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl @@ -0,0 +1,163 @@ + +/** + * Gather Filter pass: Filter the gather pass result to reduce noise. + * + * This is a simple 3x3 median filter to avoid dilating highlights with a 3x3 max filter even if + * cheaper. + */ + +struct FilterSample { + vec4 color; + float weight; +}; + +/* -------------------------------------------------------------------- */ +/** \name Pixel cache. + * \{ */ + +const uint cache_size = gl_WorkGroupSize.x + 2; +shared vec4 color_cache[cache_size][cache_size]; +shared float weight_cache[cache_size][cache_size]; + +void cache_init() +{ + /** + * Load enough values into LDS to perform the filter. + * + * ┌──────────────────────────────┐ + * │ │ < Border texels that needs to be loaded. + * │ x x x x x x x x │ ─┐ + * │ x x x x x x x x │ │ + * │ x x x x x x x x │ │ + * │ x x x x x x x x │ │ Thread Group Size 8x8. + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ ─┘ + * │ L L L L L │ < Border texels that needs to be loaded. + * └──────────────────────────────┘ + * └───────────┘ + * Load using 5x5 threads. + */ + + ivec2 texel = ivec2(gl_GlobalInvocationID.xy) - 1; + if (all(lessThan(gl_LocalInvocationID.xy, uvec2(cache_size / 2u)))) { + for (int y = 0; y < 2; y++) { + for (int x = 0; x < 2; x++) { + ivec2 offset = ivec2(x, y) * ivec2(cache_size / 2u); + ivec2 cache_texel = ivec2(gl_LocalInvocationID.xy) + offset; + ivec2 load_texel = clamp(texel + offset, ivec2(0), textureSize(color_tx, 0) - 1); + + color_cache[cache_texel.y][cache_texel.x] = texelFetch(color_tx, load_texel, 0); + weight_cache[cache_texel.y][cache_texel.x] = texelFetch(weight_tx, load_texel, 0).r; + } + } + } + barrier(); +} + +FilterSample cache_sample(int x, int y) +{ + return FilterSample(color_cache[y][x], weight_cache[y][x]); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Median filter + * From: + * Implementing Median Filters in XC4000E FPGAs + * JOHN L. SMITH, Univision Technologies Inc., Billerica, MA + * http://users.utcluj.ro/~baruch/resources/Image/xl23_16.pdf + * Figure 1 + * \{ */ + +FilterSample filter_min(FilterSample a, FilterSample b) +{ + return FilterSample(min(a.color, b.color), min(a.weight, b.weight)); +} + +FilterSample filter_max(FilterSample a, FilterSample b) +{ + return FilterSample(max(a.color, b.color), max(a.weight, b.weight)); +} + +FilterSample filter_min(FilterSample a, FilterSample b, FilterSample c) +{ + return FilterSample(min(a.color, min(c.color, b.color)), min(a.weight, min(c.weight, b.weight))); +} + +FilterSample filter_max(FilterSample a, FilterSample b, FilterSample c) +{ + return FilterSample(max(a.color, max(c.color, b.color)), max(a.weight, max(c.weight, b.weight))); +} + +FilterSample filter_median(FilterSample s1, FilterSample s2, FilterSample s3) +{ + /* From diagram, with nodes numbered from top to bottom. */ + FilterSample l1 = filter_min(s2, s3); + FilterSample h1 = filter_max(s2, s3); + FilterSample h2 = filter_max(s1, l1); + FilterSample l3 = filter_min(h2, h1); + return l3; +} + +struct FilterLmhResult { + FilterSample low; + FilterSample median; + FilterSample high; +}; + +FilterLmhResult filter_lmh(FilterSample s1, FilterSample s2, FilterSample s3) +{ + /* From diagram, with nodes numbered from top to bottom. */ + FilterSample h1 = filter_max(s2, s3); + FilterSample l1 = filter_min(s2, s3); + + FilterSample h2 = filter_max(s1, l1); + FilterSample l2 = filter_min(s1, l1); + + FilterSample h3 = filter_max(h2, h1); + FilterSample l3 = filter_min(h2, h1); + + FilterLmhResult result; + result.low = l2; + result.median = l3; + result.high = h3; + + return result; +} + +/** \} */ + +void main() +{ + /** + * NOTE: We can **NOT** optimize by discarding some tiles as the result is sampled using bilinear + * filtering in the resolve pass. Not outputing to a tile means that border texels have undefined + * value and tile border will be noticeable in the final image. + */ + + cache_init(); + + ivec2 texel = ivec2(gl_LocalInvocationID.xy); + + FilterLmhResult rows[3]; + for (int y = 0; y < 3; y++) { + rows[y] = filter_lmh(cache_sample(texel.x + 0, texel.y + y), + cache_sample(texel.x + 1, texel.y + y), + cache_sample(texel.x + 2, texel.y + y)); + } + /* Left nodes. */ + FilterSample high = filter_max(rows[0].low, rows[1].low, rows[2].low); + /* Right nodes. */ + FilterSample low = filter_min(rows[0].high, rows[1].high, rows[2].high); + /* Center nodes. */ + FilterSample median = filter_median(rows[0].median, rows[1].median, rows[2].median); + /* Last bottom nodes. */ + median = filter_median(low, median, high); + + ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy); + imageStore(out_color_img, out_texel, median.color); + imageStore(out_weight_img, out_texel, vec4(median.weight)); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_gather_comp.glsl new file mode 100644 index 00000000000..e9905cd8aaf --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_gather_comp.glsl @@ -0,0 +1,99 @@ + +/** + * Gather pass: Convolve foreground and background parts in separate passes. + * + * Using the min&max CoC tile buffer, we select the best apropriate method to blur the scene color. + * A fast gather path is taken if there is not many CoC variation inside the tile. + * + * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring + * rotation to ensure maximum coverage. + * + * Outputs: + * - Color * Weight, Weight, Occlusion 'CoC' Depth (mean and variance) + **/ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_accumulator_lib.glsl) + +void main() +{ + ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy / DOF_TILES_SIZE); + CocTile coc_tile = dof_coc_tile_load(in_tiles_fg_img, in_tiles_bg_img, tile_co); + CocTilePrediction prediction = dof_coc_tile_prediction_get(coc_tile); + + float base_radius, min_radius, min_intersectable_radius; + bool can_early_out; + if (is_foreground) { + base_radius = -coc_tile.fg_min_coc; + min_radius = -coc_tile.fg_max_coc; + min_intersectable_radius = -coc_tile.fg_max_intersectable_coc; + can_early_out = !prediction.do_foreground; + } + else { + base_radius = coc_tile.bg_max_coc; + min_radius = coc_tile.bg_min_coc; + min_intersectable_radius = coc_tile.bg_min_intersectable_coc; + can_early_out = !prediction.do_background; + } + + bool do_fast_gather = dof_do_fast_gather(base_radius, min_radius, is_foreground); + + /* Gather at half resolution. Divide CoC by 2. */ + base_radius *= 0.5; + min_intersectable_radius *= 0.5; + + bool do_density_change = dof_do_density_change(base_radius, min_intersectable_radius); + + vec4 out_color; + float out_weight; + vec2 out_occlusion; + + if (can_early_out) { + out_color = vec4(0.0); + out_weight = 0.0; + out_occlusion = vec2(0.0, 0.0); + } + else if (do_fast_gather) { + dof_gather_accumulator(color_tx, + color_bilinear_tx, + coc_tx, + bokeh_lut_tx, + base_radius, + min_intersectable_radius, + true, + false, + out_color, + out_weight, + out_occlusion); + } + else if (do_density_change) { + dof_gather_accumulator(color_tx, + color_bilinear_tx, + coc_tx, + bokeh_lut_tx, + base_radius, + min_intersectable_radius, + false, + true, + out_color, + out_weight, + out_occlusion); + } + else { + dof_gather_accumulator(color_tx, + color_bilinear_tx, + coc_tx, + bokeh_lut_tx, + base_radius, + min_intersectable_radius, + false, + false, + out_color, + out_weight, + out_occlusion); + } + + ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy); + imageStore(out_color_img, out_texel, out_color); + imageStore(out_weight_img, out_texel, vec4(out_weight)); + imageStore(out_occlusion_img, out_texel, out_occlusion.xyxy); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_hole_fill_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_hole_fill_comp.glsl new file mode 100644 index 00000000000..2b664520bba --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_hole_fill_comp.glsl @@ -0,0 +1,70 @@ + +/** + * Holefill pass: Gather background parts where foreground is present. + * + * Using the min&max CoC tile buffer, we select the best apropriate method to blur the scene color. + * A fast gather path is taken if there is not many CoC variation inside the tile. + * + * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring + * rotation to ensure maximum coverage. + **/ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_accumulator_lib.glsl) + +void main() +{ + ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy / DOF_TILES_SIZE); + CocTile coc_tile = dof_coc_tile_load(in_tiles_fg_img, in_tiles_bg_img, tile_co); + CocTilePrediction prediction = dof_coc_tile_prediction_get(coc_tile); + + float base_radius = -coc_tile.fg_min_coc; + float min_radius = -coc_tile.fg_max_coc; + float min_intersectable_radius = dof_tile_large_coc; + bool can_early_out = !prediction.do_hole_fill; + + bool do_fast_gather = dof_do_fast_gather(base_radius, min_radius, is_foreground); + + /* Gather at half resolution. Divide CoC by 2. */ + base_radius *= 0.5; + min_intersectable_radius *= 0.5; + + bool do_density_change = dof_do_density_change(base_radius, min_intersectable_radius); + + vec4 out_color = vec4(0.0); + float out_weight = 0.0; + vec2 unused_occlusion = vec2(0.0, 0.0); + + if (can_early_out) { + /* Early out. */ + } + else if (do_fast_gather) { + dof_gather_accumulator(color_tx, + color_bilinear_tx, + coc_tx, + coc_tx, + base_radius, + min_intersectable_radius, + true, + false, + out_color, + out_weight, + unused_occlusion); + } + else { + dof_gather_accumulator(color_tx, + color_bilinear_tx, + coc_tx, + coc_tx, + base_radius, + min_intersectable_radius, + false, + false, + out_color, + out_weight, + unused_occlusion); + } + + ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy); + imageStore(out_color_img, out_texel, out_color); + imageStore(out_weight_img, out_texel, vec4(out_weight)); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_lib.glsl new file mode 100644 index 00000000000..f89da641446 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_lib.glsl @@ -0,0 +1,327 @@ + +/** + * Depth of Field utils. + **/ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Constants. + * \{ */ + +#ifndef DOF_SLIGHT_FOCUS_DENSITY +# define DOF_SLIGHT_FOCUS_DENSITY 2 +#endif + +#ifdef DOF_RESOLVE_PASS +const bool is_resolve = true; +#else +const bool is_resolve = false; +#endif +#ifdef DOF_FOREGROUND_PASS +const bool is_foreground = DOF_FOREGROUND_PASS; +#else +const bool is_foreground = false; +#endif +/* Debug options */ +const bool debug_gather_perf = false; +const bool debug_scatter_perf = false; +const bool debug_resolve_perf = false; + +const bool no_smooth_intersection = false; +const bool no_gather_occlusion = false; +const bool no_gather_mipmaps = false; +const bool no_gather_random = false; +const bool no_gather_filtering = false; +const bool no_scatter_occlusion = false; +const bool no_scatter_pass = false; +const bool no_foreground_pass = false; +const bool no_background_pass = false; +const bool no_slight_focus_pass = false; +const bool no_focus_pass = false; +const bool no_hole_fill_pass = false; + +/* Distribute weights between near/slightfocus/far fields (slide 117). */ +const float dof_layer_threshold = 4.0; +/* Make sure it overlaps. */ +const float dof_layer_offset_fg = 0.5 + 1.0; +/* Extra offset for convolution layers to avoid light leaking from background. */ +const float dof_layer_offset = 0.5 + 0.5; + +const int dof_max_slight_focus_radius = DOF_MAX_SLIGHT_FOCUS_RADIUS; + +const vec2 quad_offsets[4] = vec2[4]( + vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.5, -0.5), vec2(-0.5, -0.5)); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weighting and downsampling utils. + * \{ */ + +float dof_hdr_color_weight(vec4 color) +{ + /* Very fast "luma" weighting. */ + float luma = (color.g * 2.0) + (color.r + color.b); + /* TODO(fclem) Pass correct exposure. */ + const float exposure = 1.0; + return 1.0 / (luma * exposure + 4.0); +} + +float dof_coc_select(vec4 cocs) +{ + /* Select biggest coc. */ + float selected_coc = cocs.x; + if (abs(cocs.y) > abs(selected_coc)) { + selected_coc = cocs.y; + } + if (abs(cocs.z) > abs(selected_coc)) { + selected_coc = cocs.z; + } + if (abs(cocs.w) > abs(selected_coc)) { + selected_coc = cocs.w; + } + return selected_coc; +} + +/* NOTE: Do not forget to normalize weights afterwards. */ +vec4 dof_bilateral_coc_weights(vec4 cocs) +{ + float chosen_coc = dof_coc_select(cocs); + + const float scale = 4.0; /* TODO(fclem) revisit. */ + /* NOTE: The difference between the cocs should be inside a abs() function, + * but we follow UE4 implementation to improve how dithered transparency looks (see slide 19). */ + return saturate(1.0 - (chosen_coc - cocs) * scale); +} + +/* NOTE: Do not forget to normalize weights afterwards. */ +vec4 dof_bilateral_color_weights(vec4 colors[4]) +{ + vec4 weights; + for (int i = 0; i < 4; i++) { + weights[i] = dof_hdr_color_weight(colors[i]); + } + return weights; +} + +/* Returns signed Circle of confusion radius (in pixel) based on depth buffer value [0..1]. */ +float dof_coc_from_depth(DepthOfFieldData dof_data, vec2 uv, float depth) +{ + if (is_panoramic(dof_data.camera_type)) { + /* Use radial depth. */ + depth = -length(get_view_space_from_depth(uv, depth)); + } + else { + depth = get_view_z_from_depth(depth); + } + return coc_radius_from_camera_depth(dof_data, depth); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Gather & Scatter Weighting + * \{ */ + +float dof_layer_weight(float coc, const bool is_foreground) +{ + /* NOTE: These are fullres pixel CoC value. */ + if (is_resolve) { + return saturate(-abs(coc) + dof_layer_threshold + dof_layer_offset) * + float(is_foreground ? (coc <= 0.5) : (coc > -0.5)); + } + else { + coc *= 2.0; /* Account for half pixel gather. */ + float threshold = dof_layer_threshold - + ((is_foreground) ? dof_layer_offset_fg : dof_layer_offset); + return saturate(((is_foreground) ? -coc : coc) - threshold); + } +} +vec4 dof_layer_weight(vec4 coc) +{ + /* NOTE: Used for scatter pass which already flipped the sign correctly. */ + coc *= 2.0; /* Account for half pixel gather. */ + return saturate(coc - dof_layer_threshold + dof_layer_offset); +} + +/* NOTE: This is halfres CoC radius. */ +float dof_sample_weight(float coc) +{ +#if 1 /* Optimized */ + return min(1.0, 1.0 / sqr(coc)); +#else + /* Full intensity if CoC radius is below the pixel footprint. */ + const float min_coc = 1.0; + coc = max(min_coc, abs(coc)); + return (M_PI * min_coc * min_coc) / (M_PI * coc * coc); +#endif +} +vec4 dof_sample_weight(vec4 coc) +{ +#if 1 /* Optimized */ + return min(vec4(1.0), 1.0 / sqr(coc)); +#else + /* Full intensity if CoC radius is below the pixel footprint. */ + const float min_coc = 1.0; + coc = max(vec4(min_coc), abs(coc)); + return (M_PI * min_coc * min_coc) / (M_PI * coc * coc); +#endif +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle of Confusion tiles + * \{ */ + +struct CocTile { + float fg_min_coc; + float fg_max_coc; + float fg_max_intersectable_coc; + float bg_min_coc; + float bg_max_coc; + float bg_min_intersectable_coc; +}; + +/* WATCH: Might have to change depending on the texture format. */ +const float dof_tile_large_coc = 1024.0; + +/* Init a CoC tile for reduction algorithms. */ +CocTile dof_coc_tile_init() +{ + CocTile tile; + tile.fg_min_coc = 0.0; + tile.fg_max_coc = -dof_tile_large_coc; + tile.fg_max_intersectable_coc = dof_tile_large_coc; + tile.bg_min_coc = dof_tile_large_coc; + tile.bg_max_coc = 0.0; + tile.bg_min_intersectable_coc = dof_tile_large_coc; + return tile; +} + +CocTile dof_coc_tile_unpack(vec3 fg, vec3 bg) +{ + CocTile tile; + tile.fg_min_coc = -fg.x; + tile.fg_max_coc = -fg.y; + tile.fg_max_intersectable_coc = -fg.z; + tile.bg_min_coc = bg.x; + tile.bg_max_coc = bg.y; + tile.bg_min_intersectable_coc = bg.z; + return tile; +} + +/* WORKAROUND(fclem): GLSL compilers differs in what qualifiers are requires to pass images as + * parameters. Workaround by using defines. */ +#define dof_coc_tile_load(tiles_fg_img_, tiles_bg_img_, texel_) \ + dof_coc_tile_unpack( \ + imageLoad(tiles_fg_img_, clamp(texel_, ivec2(0), imageSize(tiles_fg_img_) - 1)).xyz, \ + imageLoad(tiles_bg_img_, clamp(texel_, ivec2(0), imageSize(tiles_bg_img_) - 1)).xyz) + +void dof_coc_tile_pack(CocTile tile, out vec3 out_fg, out vec3 out_bg) +{ + out_fg.x = -tile.fg_min_coc; + out_fg.y = -tile.fg_max_coc; + out_fg.z = -tile.fg_max_intersectable_coc; + out_bg.x = tile.bg_min_coc; + out_bg.y = tile.bg_max_coc; + out_bg.z = tile.bg_min_intersectable_coc; +} + +#define dof_coc_tile_store(tiles_fg_img_, tiles_bg_img_, texel_out_, tile_data_) \ + if (true) { \ + vec3 out_fg; \ + vec3 out_bg; \ + dof_coc_tile_pack(tile_data_, out_fg, out_bg); \ + imageStore(tiles_fg_img_, texel_out_, out_fg.xyzz); \ + imageStore(tiles_bg_img_, texel_out_, out_bg.xyzz); \ + } + +bool dof_do_fast_gather(float max_absolute_coc, float min_absolute_coc, const bool is_foreground) +{ + float min_weight = dof_layer_weight((is_foreground) ? -min_absolute_coc : min_absolute_coc, + is_foreground); + if (min_weight < 1.0) { + return false; + } + /* FIXME(fclem): This is a workaround to fast gather triggering too early. Since we use custom + * opacity mask, the opacity is not given to be 100% even for after normal threshold. */ + if (is_foreground && min_absolute_coc < dof_layer_threshold) { + return false; + } + return (max_absolute_coc - min_absolute_coc) < (DOF_FAST_GATHER_COC_ERROR * max_absolute_coc); +} + +struct CocTilePrediction { + bool do_foreground; + bool do_slight_focus; + bool do_focus; + bool do_background; + bool do_hole_fill; +}; + +/** + * Using the tile CoC infos, predict which convolutions are required and the ones that can be + * skipped. + */ +CocTilePrediction dof_coc_tile_prediction_get(CocTile tile) +{ + /* Based on tile value, predict what pass we need to load. */ + CocTilePrediction predict; + + predict.do_foreground = (-tile.fg_min_coc > dof_layer_threshold - dof_layer_offset_fg); + bool fg_fully_opaque = predict.do_foreground && + dof_do_fast_gather(-tile.fg_min_coc, -tile.fg_max_coc, true); + predict.do_background = !fg_fully_opaque && + (tile.bg_max_coc > dof_layer_threshold - dof_layer_offset); + bool bg_fully_opaque = predict.do_background && + dof_do_fast_gather(-tile.bg_max_coc, tile.bg_min_coc, false); + predict.do_hole_fill = !fg_fully_opaque && -tile.fg_min_coc > 0.0; + predict.do_focus = !fg_fully_opaque; + predict.do_slight_focus = !fg_fully_opaque; + +#if 0 /* Debug */ + predict.do_foreground = predict.do_background = predict.do_hole_fill = true; +#endif + return predict; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Gathering + * \{ */ + +/** + * Generate samples in a square pattern with the ring radius. X is the center tile. + * + * Dist1 Dist2 + * 6 5 4 3 2 + * 3 2 1 7 1 + * . X 0 . X 0 + * . . . . . + * . . . . . + * + * Samples are expected to be mirrored to complete the pattern. + **/ +ivec2 dof_square_ring_sample_offset(int ring_distance, int sample_id) +{ + ivec2 offset; + if (sample_id < ring_distance) { + offset.x = ring_distance; + offset.y = sample_id; + } + else if (sample_id < ring_distance * 3) { + offset.x = ring_distance - sample_id + ring_distance; + offset.y = ring_distance; + } + else { + offset.x = -ring_distance; + offset.y = ring_distance - sample_id + 3 * ring_distance; + } + return offset; +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_reduce_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_reduce_comp.glsl new file mode 100644 index 00000000000..c757e8304ac --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_reduce_comp.glsl @@ -0,0 +1,247 @@ + +/** + * Reduce copy pass: filter fireflies and split color between scatter and gather input. + * + * NOTE: The texture can end up being too big because of the mipmap padding. We correct for + * that during the convolution phase. + * + * Inputs: + * - Output of setup pass (halfres) and reduce downsample pass (quarter res). + * Outputs: + * - Halfres padded to avoid mipmap mis-alignment (so possibly not matching input size). + * - Gather input color (whole mip chain), Scatter rect list, Signed CoC (whole mip chain). + **/ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +/* NOTE: Do not compare alpha as it is not scattered by the scatter pass. */ +float dof_scatter_neighborhood_rejection(vec3 color) +{ + color = min(vec3(dof_buf.scatter_neighbor_max_color), color); + + float validity = 0.0; + + /* Centered in the middle of 4 quarter res texel. */ + vec2 texel_size = 1.0 / vec2(textureSize(downsample_tx, 0).xy); + vec2 uv = ((vec2(gl_GlobalInvocationID.xy) + 0.5) * 0.5) * texel_size; + + vec3 max_diff = vec3(0.0); + for (int i = 0; i < 4; i++) { + vec2 sample_uv = uv + quad_offsets[i] * texel_size; + vec3 ref = textureLod(downsample_tx, sample_uv, 0.0).rgb; + + ref = min(vec3(dof_buf.scatter_neighbor_max_color), ref); + float diff = max_v3(max(vec3(0.0), abs(ref - color))); + + const float rejection_threshold = 0.7; + diff = saturate(diff / rejection_threshold - 1.0); + validity = max(validity, diff); + } + + return validity; +} + +/* This avoids Bokeh sprite popping in and out at the screen border and + * drawing Bokeh sprites larger than the screen. */ +float dof_scatter_screen_border_rejection(float coc, ivec2 texel) +{ + vec2 screen_size = vec2(imageSize(inout_color_lod0_img)); + vec2 uv = (vec2(texel) + 0.5) / screen_size; + vec2 screen_pos = uv * screen_size; + float min_screen_border_distance = min_v2(min(screen_pos, screen_size - screen_pos)); + /* Fullres to halfres CoC. */ + coc *= 0.5; + /* Allow 10px transition. */ + const float rejection_hardeness = 1.0 / 10.0; + return saturate((min_screen_border_distance - abs(coc)) * rejection_hardeness + 1.0); +} + +float dof_scatter_luminosity_rejection(vec3 color) +{ + const float rejection_hardness = 1.0; + return saturate(max_v3(color - dof_buf.scatter_color_threshold) * rejection_hardness); +} + +float dof_scatter_coc_radius_rejection(float coc) +{ + const float rejection_hardness = 0.3; + return saturate((abs(coc) - dof_buf.scatter_coc_threshold) * rejection_hardness); +} + +float fast_luma(vec3 color) +{ + return (2.0 * color.g) + color.r + color.b; +} + +const uint cache_size = gl_WorkGroupSize.x; +shared vec4 color_cache[cache_size][cache_size]; +shared float coc_cache[cache_size][cache_size]; +shared float do_scatter[cache_size][cache_size]; + +void main() +{ + ivec2 texel = min(ivec2(gl_GlobalInvocationID.xy), imageSize(inout_color_lod0_img) - 1); + uvec2 texel_local = gl_LocalInvocationID.xy; + /* Increase readablility. */ +#define LOCAL_INDEX texel_local.y][texel_local.x +#define LOCAL_OFFSET(x_, y_) texel_local.y + (y_)][texel_local.x + (x_) + + /* Load level 0 into cache. */ + color_cache[LOCAL_INDEX] = imageLoad(inout_color_lod0_img, texel); + coc_cache[LOCAL_INDEX] = imageLoad(in_coc_lod0_img, texel).r; + + /* Only scatter if luminous enough. */ + do_scatter[LOCAL_INDEX] = dof_scatter_luminosity_rejection(color_cache[LOCAL_INDEX].rgb); + /* Only scatter if CoC is big enough. */ + do_scatter[LOCAL_INDEX] *= dof_scatter_coc_radius_rejection(coc_cache[LOCAL_INDEX]); + /* Only scatter if CoC is not too big to avoid performance issues. */ + do_scatter[LOCAL_INDEX] *= dof_scatter_screen_border_rejection(coc_cache[LOCAL_INDEX], texel); + /* Only scatter if neighborhood is different enough. */ + do_scatter[LOCAL_INDEX] *= dof_scatter_neighborhood_rejection(color_cache[LOCAL_INDEX].rgb); + /* For debuging. */ + if (no_scatter_pass) { + do_scatter[LOCAL_INDEX] = 0.0; + } + + barrier(); + + /* Add a scatter sprite for each 2x2 pixel neighborhood passing the threshold. */ + if (all(equal(texel_local & 1u, uvec2(0)))) { + vec4 do_scatter4; + /* Follows quad_offsets order. */ + do_scatter4.x = do_scatter[LOCAL_OFFSET(0, 1)]; + do_scatter4.y = do_scatter[LOCAL_OFFSET(1, 1)]; + do_scatter4.z = do_scatter[LOCAL_OFFSET(1, 0)]; + do_scatter4.w = do_scatter[LOCAL_OFFSET(0, 0)]; + if (any(greaterThan(do_scatter4, vec4(0.0)))) { + /* Apply energy conservation to anamorphic scattered bokeh. */ + do_scatter4 *= max_v2(dof_buf.bokeh_anisotropic_scale_inv); + + /* Circle of Confusion. */ + vec4 coc4; + coc4.x = coc_cache[LOCAL_OFFSET(0, 1)]; + coc4.y = coc_cache[LOCAL_OFFSET(1, 1)]; + coc4.z = coc_cache[LOCAL_OFFSET(1, 0)]; + coc4.w = coc_cache[LOCAL_OFFSET(0, 0)]; + /* We are scattering at half resolution, so divide CoC by 2. */ + coc4 *= 0.5; + /* Sprite center position. Center sprite around the 4 texture taps. */ + vec2 offset = vec2(gl_GlobalInvocationID.xy) + 1; + /* Add 2.5 to max_coc because the max_coc may not be centered on the sprite origin + * and because we smooth the bokeh shape a bit in the pixel shader. */ + vec2 half_extent = max_v4(abs(coc4)) * dof_buf.bokeh_anisotropic_scale + 2.5; + /* Issue a sprite for each field if any CoC matches. */ + if (any(lessThan(do_scatter4 * sign(coc4), vec4(0.0)))) { + /* Same value for all threads. Not an issue if we don't sync access to it. */ + scatter_fg_indirect_buf.v_count = 4u; + /* Issue 1 strip instance per sprite. */ + uint rect_id = atomicAdd(scatter_fg_indirect_buf.i_count, 1u); + if (rect_id < dof_buf.scatter_max_rect) { + + vec4 coc4_fg = max(vec4(0.0), -coc4); + vec4 fg_weights = dof_layer_weight(coc4_fg) * dof_sample_weight(coc4_fg) * do_scatter4; + /* Filter NaNs. */ + fg_weights = select(fg_weights, vec4(0.0), equal(coc4_fg, vec4(0.0))); + + ScatterRect rect_fg; + rect_fg.offset = offset; + /* Negate extent to flip the sprite. Mimics optical phenomenon. */ + rect_fg.half_extent = -half_extent; + /* NOTE: Since we fliped the quad along (1,-1) line, we need to also swap the (1,1) and + * (0,0) values so that quad_offsets is in the right order in the vertex shader. */ + + /* Circle of Confusion absolute radius in halfres pixels. */ + rect_fg.color_and_coc[0].a = coc4_fg[0]; + rect_fg.color_and_coc[1].a = coc4_fg[3]; + rect_fg.color_and_coc[2].a = coc4_fg[2]; + rect_fg.color_and_coc[3].a = coc4_fg[1]; + /* Apply weights. */ + rect_fg.color_and_coc[0].rgb = color_cache[LOCAL_OFFSET(0, 1)].rgb * fg_weights[0]; + rect_fg.color_and_coc[1].rgb = color_cache[LOCAL_OFFSET(0, 0)].rgb * fg_weights[3]; + rect_fg.color_and_coc[2].rgb = color_cache[LOCAL_OFFSET(1, 0)].rgb * fg_weights[2]; + rect_fg.color_and_coc[3].rgb = color_cache[LOCAL_OFFSET(1, 1)].rgb * fg_weights[1]; + + scatter_fg_list_buf[rect_id] = rect_fg; + } + } + if (any(greaterThan(do_scatter4 * sign(coc4), vec4(0.0)))) { + /* Same value for all threads. Not an issue if we don't sync access to it. */ + scatter_bg_indirect_buf.v_count = 4u; + /* Issue 1 strip instance per sprite. */ + uint rect_id = atomicAdd(scatter_bg_indirect_buf.i_count, 1u); + if (rect_id < dof_buf.scatter_max_rect) { + vec4 coc4_bg = max(vec4(0.0), coc4); + vec4 bg_weights = dof_layer_weight(coc4_bg) * dof_sample_weight(coc4_bg) * do_scatter4; + /* Filter NaNs. */ + bg_weights = select(bg_weights, vec4(0.0), equal(coc4_bg, vec4(0.0))); + + ScatterRect rect_bg; + rect_bg.offset = offset; + rect_bg.half_extent = half_extent; + + /* Circle of Confusion absolute radius in halfres pixels. */ + rect_bg.color_and_coc[0].a = coc4_bg[0]; + rect_bg.color_and_coc[1].a = coc4_bg[1]; + rect_bg.color_and_coc[2].a = coc4_bg[2]; + rect_bg.color_and_coc[3].a = coc4_bg[3]; + /* Apply weights. */ + rect_bg.color_and_coc[0].rgb = color_cache[LOCAL_OFFSET(0, 1)].rgb * bg_weights[0]; + rect_bg.color_and_coc[1].rgb = color_cache[LOCAL_OFFSET(1, 1)].rgb * bg_weights[1]; + rect_bg.color_and_coc[2].rgb = color_cache[LOCAL_OFFSET(1, 0)].rgb * bg_weights[2]; + rect_bg.color_and_coc[3].rgb = color_cache[LOCAL_OFFSET(0, 0)].rgb * bg_weights[3]; + + scatter_bg_list_buf[rect_id] = rect_bg; + } + } + } + } + + /* Remove scatter color from gather. */ + color_cache[LOCAL_INDEX].rgb *= 1.0 - do_scatter[LOCAL_INDEX]; + imageStore(inout_color_lod0_img, texel, color_cache[LOCAL_INDEX]); + + /* Recursive downsample. */ + for (uint i = 1u; i < DOF_MIP_COUNT; i++) { + barrier(); + uint mask = ~(~0u << i); + if (all(equal(gl_LocalInvocationID.xy & mask, uvec2(0)))) { + uint ofs = 1u << (i - 1u); + + /* TODO(fclem): Could use wave shuffle intrinsics to avoid LDS as suggested by the paper. */ + vec4 coc4; + coc4.x = coc_cache[LOCAL_OFFSET(0, ofs)]; + coc4.y = coc_cache[LOCAL_OFFSET(ofs, ofs)]; + coc4.z = coc_cache[LOCAL_OFFSET(ofs, 0)]; + coc4.w = coc_cache[LOCAL_OFFSET(0, 0)]; + + vec4 colors[4]; + colors[0] = color_cache[LOCAL_OFFSET(0, ofs)]; + colors[1] = color_cache[LOCAL_OFFSET(ofs, ofs)]; + colors[2] = color_cache[LOCAL_OFFSET(ofs, 0)]; + colors[3] = color_cache[LOCAL_OFFSET(0, 0)]; + + vec4 weights = dof_bilateral_coc_weights(coc4); + weights *= dof_bilateral_color_weights(colors); + /* Normalize so that the sum is 1. */ + weights *= safe_rcp(sum(weights)); + + color_cache[LOCAL_INDEX] = weighted_sum_array(colors, weights); + coc_cache[LOCAL_INDEX] = dot(coc4, weights); + + ivec2 texel = ivec2(gl_GlobalInvocationID.xy >> i); + + if (i == 1) { + imageStore(out_color_lod1_img, texel, color_cache[LOCAL_INDEX]); + imageStore(out_coc_lod1_img, texel, vec4(coc_cache[LOCAL_INDEX])); + } + else if (i == 2) { + imageStore(out_color_lod2_img, texel, color_cache[LOCAL_INDEX]); + imageStore(out_coc_lod2_img, texel, vec4(coc_cache[LOCAL_INDEX])); + } + else /* if (i == 3) */ { + imageStore(out_color_lod3_img, texel, color_cache[LOCAL_INDEX]); + imageStore(out_coc_lod3_img, texel, vec4(coc_cache[LOCAL_INDEX])); + } + } + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_resolve_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_resolve_comp.glsl new file mode 100644 index 00000000000..d21f6d69541 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_resolve_comp.glsl @@ -0,0 +1,178 @@ + +/** + * Recombine Pass: Load separate convolution layer and composite with self + * slight defocus convolution and in-focus fields. + * + * The halfres gather methods are fast but lack precision for small CoC areas. + * To fix this we do a bruteforce gather to have a smooth transition between + * in-focus and defocus regions. + */ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_accumulator_lib.glsl) + +shared uint shared_max_slight_focus_abs_coc; + +/** + * Returns The max CoC in the Slight Focus range inside this compute tile. + */ +float dof_slight_focus_coc_tile_get(vec2 frag_coord) +{ + if (all(equal(gl_LocalInvocationID, uvec3(0)))) { + shared_max_slight_focus_abs_coc = floatBitsToUint(0.0); + } + barrier(); + + float local_abs_max = 0.0; + /* Sample in a cross (X) pattern. This covers all pixels over the whole tile, as long as + * dof_max_slight_focus_radius is less than the group size. */ + for (int i = 0; i < 4; i++) { + vec2 sample_uv = (frag_coord + quad_offsets[i] * 2.0 * dof_max_slight_focus_radius) / + vec2(textureSize(color_tx, 0)); + float coc = dof_coc_from_depth(dof_buf, sample_uv, textureLod(depth_tx, sample_uv, 0.0).r); + coc = clamp(coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max); + if (abs(coc) < dof_max_slight_focus_radius) { + local_abs_max = max(local_abs_max, abs(coc)); + } + } + /* Use atomic reduce operation. */ + atomicMax(shared_max_slight_focus_abs_coc, floatBitsToUint(local_abs_max)); + /* "Broadcast" result accross all threads. */ + barrier(); + + return uintBitsToFloat(shared_max_slight_focus_abs_coc); +} + +vec3 dof_neighborhood_clamp(vec2 frag_coord, vec3 color, float center_coc, float weight) +{ + /* Stabilize color by clamping with the stable half res neighboorhood. */ + vec3 neighbor_min, neighbor_max; + const vec2 corners[4] = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1)); + for (int i = 0; i < 4; i++) { + /** + * Visit the 4 half-res texels around (and containing) the fullres texel. + * Here a diagram of a fullscreen texel (f) in the bottom left corner of a half res texel. + * We sample the stable half-resolution texture at the 4 location denoted by (h). + * ┌───────┬───────┐ + * │ h │ h │ + * │ │ │ + * │ │ f │ + * ├───────┼───────┤ + * │ h │ h │ + * │ │ │ + * │ │ │ + * └───────┴───────┘ + */ + vec2 uv_sample = ((frag_coord + corners[i]) * 0.5) / vec2(textureSize(stable_color_tx, 0)); + /* Reminder: The content of this buffer is YCoCg + CoC. */ + vec3 ycocg_sample = textureLod(stable_color_tx, uv_sample, 0.0).rgb; + neighbor_min = (i == 0) ? ycocg_sample : min(neighbor_min, ycocg_sample); + neighbor_max = (i == 0) ? ycocg_sample : max(neighbor_max, ycocg_sample); + } + /* Pad the bounds in the near in focus region to get back a bit of detail. */ + float padding = 0.125 * saturate(1.0 - sqr(center_coc) / sqr(8.0)); + neighbor_max += abs(neighbor_min) * padding; + neighbor_min -= abs(neighbor_min) * padding; + /* Progressively apply the clamp to avoid harsh transition. Also mask by weight. */ + float fac = saturate(sqr(center_coc) * 4.0) * weight; + /* Clamp in YCoCg space to avoid too much color drift. */ + color = colorspace_YCoCg_from_scene_linear(color); + color = mix(color, clamp(color, neighbor_min, neighbor_max), fac); + color = colorspace_scene_linear_from_YCoCg(color); + return color; +} + +void main() +{ + vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; + ivec2 tile_co = ivec2(frag_coord / float(DOF_TILES_SIZE * 2)); + + CocTile coc_tile = dof_coc_tile_load(in_tiles_fg_img, in_tiles_bg_img, tile_co); + CocTilePrediction prediction = dof_coc_tile_prediction_get(coc_tile); + + vec2 uv = frag_coord / vec2(textureSize(color_tx, 0)); + vec2 uv_halfres = (frag_coord * 0.5) / vec2(textureSize(color_bg_tx, 0)); + + float slight_focus_max_coc = 0.0; + if (prediction.do_slight_focus) { + slight_focus_max_coc = dof_slight_focus_coc_tile_get(frag_coord); + prediction.do_slight_focus = slight_focus_max_coc >= 0.5; + if (prediction.do_slight_focus) { + prediction.do_focus = false; + } + } + + if (prediction.do_focus) { + float center_coc = (dof_coc_from_depth(dof_buf, uv, textureLod(depth_tx, uv, 0.0).r)); + prediction.do_focus = abs(center_coc) <= 0.5; + } + + vec4 out_color = vec4(0.0); + float weight = 0.0; + + vec4 layer_color; + float layer_weight; + + if (!no_hole_fill_pass && prediction.do_hole_fill) { + layer_color = textureLod(color_hole_fill_tx, uv_halfres, 0.0); + layer_weight = textureLod(weight_hole_fill_tx, uv_halfres, 0.0).r; + out_color = layer_color * safe_rcp(layer_weight); + weight = float(layer_weight > 0.0); + } + + if (!no_background_pass && prediction.do_background) { + layer_color = textureLod(color_bg_tx, uv_halfres, 0.0); + layer_weight = textureLod(weight_bg_tx, uv_halfres, 0.0).r; + /* Always prefer background to hole_fill pass. */ + layer_color *= safe_rcp(layer_weight); + layer_weight = float(layer_weight > 0.0); + /* Composite background. */ + out_color = out_color * (1.0 - layer_weight) + layer_color; + weight = weight * (1.0 - layer_weight) + layer_weight; + /* Fill holes with the composited background. */ + out_color *= safe_rcp(weight); + weight = float(weight > 0.0); + } + + if (!no_slight_focus_pass && prediction.do_slight_focus) { + float center_coc; + dof_slight_focus_gather(depth_tx, + color_tx, + bokeh_lut_tx, + slight_focus_max_coc, + layer_color, + layer_weight, + center_coc); + + /* Composite slight defocus. */ + out_color = out_color * (1.0 - layer_weight) + layer_color; + weight = weight * (1.0 - layer_weight) + layer_weight; + + out_color.rgb = dof_neighborhood_clamp(frag_coord, out_color.rgb, center_coc, layer_weight); + } + + if (!no_focus_pass && prediction.do_focus) { + layer_color = safe_color(textureLod(color_tx, uv, 0.0)); + layer_weight = 1.0; + /* Composite in focus. */ + out_color = out_color * (1.0 - layer_weight) + layer_color; + weight = weight * (1.0 - layer_weight) + layer_weight; + } + + if (!no_foreground_pass && prediction.do_foreground) { + layer_color = textureLod(color_fg_tx, uv_halfres, 0.0); + layer_weight = textureLod(weight_fg_tx, uv_halfres, 0.0).r; + /* Composite foreground. */ + out_color = out_color * (1.0 - layer_weight) + layer_color; + } + + /* Fix float precision issue in alpha compositing. */ + if (out_color.a > 0.99) { + out_color.a = 1.0; + } + + if (debug_resolve_perf && prediction.do_slight_focus) { + out_color.rgb *= vec3(1.0, 0.1, 0.1); + } + + imageStore(out_color_img, ivec2(gl_GlobalInvocationID.xy), out_color); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_frag.glsl new file mode 100644 index 00000000000..cfb7fd2568b --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_frag.glsl @@ -0,0 +1,62 @@ + +/** + * Scatter pass: Use sprites to scatter the color of very bright pixel to have higher quality blur. + * + * We only scatter one quad per sprite and one sprite per 4 pixels to reduce vertex shader + * invocations and overdraw. + */ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0)) + +void main() +{ + vec4 coc4 = vec4(interp.color_and_coc1.w, + interp.color_and_coc2.w, + interp.color_and_coc3.w, + interp.color_and_coc4.w); + vec4 shapes; + if (use_bokeh_lut) { + shapes = vec4(texture(bokeh_lut_tx, interp.rect_uv1).r, + texture(bokeh_lut_tx, interp.rect_uv2).r, + texture(bokeh_lut_tx, interp.rect_uv3).r, + texture(bokeh_lut_tx, interp.rect_uv4).r); + } + else { + shapes = vec4(length(interp.rect_uv1), + length(interp.rect_uv2), + length(interp.rect_uv3), + length(interp.rect_uv4)); + } + shapes *= interp.distance_scale; + /* Becomes signed distance field in pixel units. */ + shapes -= coc4; + /* Smooth the edges a bit to fade out the undersampling artifacts. */ + shapes = saturate(1.0 - linearstep(-0.8, 0.8, shapes)); + /* Outside of bokeh shape. Try to avoid overloading ROPs. */ + if (max_v4(shapes) == 0.0) { + discard; + } + + if (!no_scatter_occlusion) { + /* Works because target is the same size as occlusion_tx. */ + vec2 uv = gl_FragCoord.xy / vec2(textureSize(occlusion_tx, 0).xy); + vec2 occlusion_data = texture(occlusion_tx, uv).rg; + /* Fix tilling artifacts. (Slide 90) */ + const float correction_fac = 1.0 - DOF_FAST_GATHER_COC_ERROR; + /* Occlude the sprite with geometry from the same field using a chebychev test (slide 85). */ + float mean = occlusion_data.x; + float variance = occlusion_data.y; + shapes *= variance * safe_rcp(variance + sqr(max(coc4 * correction_fac - mean, 0.0))); + } + + out_color = (interp.color_and_coc1 * shapes[0] + interp.color_and_coc2 * shapes[1] + + interp.color_and_coc3 * shapes[2] + interp.color_and_coc4 * shapes[3]); + /* Do not accumulate alpha. This has already been accumulated by the gather pass. */ + out_color.a = 0.0; + + if (debug_scatter_perf) { + out_color.rgb = avg(out_color.rgb) * vec3(1.0, 0.0, 0.0); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_vert.glsl new file mode 100644 index 00000000000..d870496a06c --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_scatter_vert.glsl @@ -0,0 +1,45 @@ + +/** + * Scatter pass: Use sprites to scatter the color of very bright pixel to have higher quality blur. + * + * We only scatter one triangle per sprite and one sprite per 4 pixels to reduce vertex shader + * invocations and overdraw. + **/ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +void main() +{ + ScatterRect rect = scatter_list_buf[gl_InstanceID]; + + interp.color_and_coc1 = rect.color_and_coc[0]; + interp.color_and_coc2 = rect.color_and_coc[1]; + interp.color_and_coc3 = rect.color_and_coc[2]; + interp.color_and_coc4 = rect.color_and_coc[3]; + + vec2 uv = vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0 - 1.0; + uv = uv * rect.half_extent; + + gl_Position = vec4(uv + rect.offset, 0.0, 1.0); + /* NDC range [-1..1]. */ + gl_Position.xy = (gl_Position.xy / vec2(textureSize(occlusion_tx, 0).xy)) * 2.0 - 1.0; + + if (use_bokeh_lut) { + /* Bias scale to avoid sampling at the texture's border. */ + interp.distance_scale = (float(DOF_BOKEH_LUT_SIZE) / float(DOF_BOKEH_LUT_SIZE - 1)); + vec2 uv_div = 1.0 / (interp.distance_scale * abs(rect.half_extent)); + interp.rect_uv1 = ((uv + quad_offsets[0]) * uv_div) * 0.5 + 0.5; + interp.rect_uv2 = ((uv + quad_offsets[1]) * uv_div) * 0.5 + 0.5; + interp.rect_uv3 = ((uv + quad_offsets[2]) * uv_div) * 0.5 + 0.5; + interp.rect_uv4 = ((uv + quad_offsets[3]) * uv_div) * 0.5 + 0.5; + /* Only for sampling. */ + interp.distance_scale *= max_v2(abs(rect.half_extent)); + } + else { + interp.distance_scale = 1.0; + interp.rect_uv1 = uv + quad_offsets[0]; + interp.rect_uv2 = uv + quad_offsets[1]; + interp.rect_uv3 = uv + quad_offsets[2]; + interp.rect_uv4 = uv + quad_offsets[3]; + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_setup_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_setup_comp.glsl new file mode 100644 index 00000000000..c017a5aa965 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_setup_comp.glsl @@ -0,0 +1,46 @@ + +/** + * Setup pass: CoC and luma aware downsample to half resolution of the input scene color buffer. + * + * An addition to the downsample CoC, we output the maximum slight out of focus CoC to be + * sure we don't miss a pixel. + * + * Input: + * Full-resolution color & depth buffer + * Output: + * Half-resolution Color, signed CoC (out_coc.x), and max slight focus abs CoC (out_coc.y). + **/ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +void main() +{ + vec2 fullres_texel_size = 1.0 / vec2(textureSize(color_tx, 0).xy); + /* Center uv around the 4 fullres pixels. */ + vec2 quad_center = vec2(gl_GlobalInvocationID.xy * 2 + 1) * fullres_texel_size; + + vec4 colors[4]; + vec4 cocs; + for (int i = 0; i < 4; i++) { + vec2 sample_uv = quad_center + quad_offsets[i] * fullres_texel_size; + /* NOTE: We use samplers without filtering. */ + colors[i] = safe_color(textureLod(color_tx, sample_uv, 0.0)); + cocs[i] = dof_coc_from_depth(dof_buf, sample_uv, textureLod(depth_tx, sample_uv, 0.0).r); + } + + cocs = clamp(cocs, -dof_buf.coc_abs_max, dof_buf.coc_abs_max); + + vec4 weights = dof_bilateral_coc_weights(cocs); + weights *= dof_bilateral_color_weights(colors); + /* Normalize so that the sum is 1. */ + weights *= safe_rcp(sum(weights)); + + ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy); + vec4 out_color = weighted_sum_array(colors, weights); + imageStore(out_color_img, out_texel, out_color); + + float out_coc = dot(cocs, weights); + imageStore(out_coc_img, out_texel, vec4(out_coc)); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_stabilize_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_stabilize_comp.glsl new file mode 100644 index 00000000000..b22af0e88f0 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_stabilize_comp.glsl @@ -0,0 +1,367 @@ + +/** + * Temporal Stabilization of the Depth of field input. + * Corresponds to the TAA pass in the paper. + * We actually duplicate the TAA logic but with a few changes: + * - We run this pass at half resolution. + * - We store CoC instead of Opacity in the alpha channel of the history. + * + * This is and adaption of the code found in eevee_film_lib.glsl + * + * Inputs: + * - Output of setup pass (halfres). + * Outputs: + * - Stabilized Color and CoC (halfres). + **/ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) + +struct DofSample { + vec4 color; + float coc; +}; + +/* -------------------------------------------------------------------- */ +/** \name LDS Cache + * \{ */ + +const uint cache_size = gl_WorkGroupSize.x + 2; +shared vec4 color_cache[cache_size][cache_size]; +shared float coc_cache[cache_size][cache_size]; +/* Need 2 pixel border for depth. */ +const uint cache_depth_size = gl_WorkGroupSize.x + 4; +shared float depth_cache[cache_depth_size][cache_depth_size]; + +void dof_cache_init() +{ + /** + * Load enough values into LDS to perform the filter. + * + * ┌──────────────────────────────┐ + * │ │ < Border texels that needs to be loaded. + * │ x x x x x x x x │ ─┐ + * │ x x x x x x x x │ │ + * │ x x x x x x x x │ │ + * │ x x x x x x x x │ │ Thread Group Size 8x8. + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ │ + * │ L L L L L x x x x │ ─┘ + * │ L L L L L │ < Border texels that needs to be loaded. + * └──────────────────────────────┘ + * └───────────┘ + * Load using 5x5 threads. + */ + + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + for (int y = 0; y < 2; y++) { + for (int x = 0; x < 2; x++) { + /* 1 Pixel border. */ + if (all(lessThan(gl_LocalInvocationID.xy, uvec2(cache_size / 2u)))) { + ivec2 offset = ivec2(x, y) * ivec2(cache_size / 2u); + ivec2 cache_texel = ivec2(gl_LocalInvocationID.xy) + offset; + ivec2 load_texel = clamp(texel + offset - 1, ivec2(0), textureSize(color_tx, 0) - 1); + + vec4 color = texelFetch(color_tx, load_texel, 0); + color_cache[cache_texel.y][cache_texel.x] = colorspace_YCoCg_from_scene_linear(color); + coc_cache[cache_texel.y][cache_texel.x] = texelFetch(coc_tx, load_texel, 0).x; + } + /* 2 Pixels border. */ + if (all(lessThan(gl_LocalInvocationID.xy, uvec2(cache_depth_size / 2u)))) { + ivec2 offset = ivec2(x, y) * ivec2(cache_depth_size / 2u); + ivec2 cache_texel = ivec2(gl_LocalInvocationID.xy) + offset; + /* Depth is fullres. Load every 2 pixels. */ + ivec2 load_texel = clamp((texel + offset - 2) * 2, ivec2(0), textureSize(depth_tx, 0) - 1); + + depth_cache[cache_texel.y][cache_texel.x] = texelFetch(depth_tx, load_texel, 0).x; + } + } + } + barrier(); +} + +/* Note: Sample color space is already in YCoCg space. */ +DofSample dof_fetch_input_sample(ivec2 offset) +{ + ivec2 coord = offset + 1 + ivec2(gl_LocalInvocationID.xy); + return DofSample(color_cache[coord.y][coord.x], coc_cache[coord.y][coord.x]); +} + +float dof_fetch_half_depth(ivec2 offset) +{ + ivec2 coord = offset + 2 + ivec2(gl_LocalInvocationID.xy); + return depth_cache[coord.y][coord.x]; +} + +/** \} */ + +float dof_luma_weight(float luma) +{ + /* Slide 20 of "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014. */ + /* To preserve more details in dark areas, we use a bigger bias. */ + const float exposure_scale = 1.0; /* TODO. */ + return 1.0 / (4.0 + luma * exposure_scale); +} + +float dof_bilateral_weight(float reference_coc, float sample_coc) +{ + /* NOTE: The difference between the cocs should be inside a abs() function, + * but we follow UE4 implementation to improve how dithered transparency looks (see slide 19). + * Effectively bleed background into foreground. + * Compared to dof_bilateral_coc_weights() this saturates as 2x the reference CoC. */ + return saturate(1.0 - (sample_coc - reference_coc) / max(1.0, abs(reference_coc))); +} + +DofSample dof_spatial_filtering() +{ + /* Plus (+) shape offsets. */ + const ivec2 plus_offsets[4] = ivec2[4](ivec2(-1, 0), ivec2(0, -1), ivec2(1, 0), ivec2(0, 1)); + DofSample center = dof_fetch_input_sample(ivec2(0)); + DofSample accum = DofSample(vec4(0.0), 0.0); + float accum_weight = 0.0; + for (int i = 0; i < 4; i++) { + DofSample samp = dof_fetch_input_sample(plus_offsets[i]); + float weight = dof_buf.filter_samples_weight[i] * dof_luma_weight(samp.color.x) * + dof_bilateral_weight(center.coc, samp.coc); + + accum.color += samp.color * weight; + accum.coc += samp.coc * weight; + accum_weight += weight; + } + /* Accumulate center sample last as it does not need bilateral_weights. */ + float weight = dof_buf.filter_center_weight * dof_luma_weight(center.color.x); + accum.color += center.color * weight; + accum.coc += center.coc * weight; + accum_weight += weight; + + float rcp_weight = 1.0 / accum_weight; + accum.color *= rcp_weight; + accum.coc *= rcp_weight; + return accum; +} + +struct DofNeighborhoodMinMax { + DofSample min; + DofSample max; +}; + +/* Return history clipping bounding box in YCoCg color space. */ +DofNeighborhoodMinMax dof_neighbor_boundbox() +{ + /* Plus (+) shape offsets. */ + const ivec2 plus_offsets[4] = ivec2[4](ivec2(-1, 0), ivec2(0, -1), ivec2(1, 0), ivec2(0, 1)); + /** + * Simple bounding box calculation in YCoCg as described in: + * "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 + */ + DofSample min_c = dof_fetch_input_sample(ivec2(0)); + DofSample max_c = min_c; + for (int i = 0; i < 4; i++) { + DofSample samp = dof_fetch_input_sample(plus_offsets[i]); + min_c.color = min(min_c.color, samp.color); + max_c.color = max(max_c.color, samp.color); + min_c.coc = min(min_c.coc, samp.coc); + max_c.coc = max(max_c.coc, samp.coc); + } + /* (Slide 32) Simple clamp to min/max of 8 neighbors results in 3x3 box artifacts. + * Round bbox shape by averaging 2 different min/max from 2 different neighborhood. */ + DofSample min_c_3x3 = min_c; + DofSample max_c_3x3 = max_c; + const ivec2 corners[4] = ivec2[4](ivec2(-1, -1), ivec2(1, -1), ivec2(-1, 1), ivec2(1, 1)); + for (int i = 0; i < 4; i++) { + DofSample samp = dof_fetch_input_sample(corners[i]); + min_c_3x3.color = min(min_c_3x3.color, samp.color); + max_c_3x3.color = max(max_c_3x3.color, samp.color); + min_c_3x3.coc = min(min_c_3x3.coc, samp.coc); + max_c_3x3.coc = max(max_c_3x3.coc, samp.coc); + } + min_c.color = (min_c.color + min_c_3x3.color) * 0.5; + max_c.color = (max_c.color + max_c_3x3.color) * 0.5; + min_c.coc = (min_c.coc + min_c_3x3.coc) * 0.5; + max_c.coc = (max_c.coc + max_c_3x3.coc) * 0.5; + + return DofNeighborhoodMinMax(min_c, max_c); +} + +/* Returns motion in pixel space to retrieve the pixel history. */ +vec2 dof_pixel_history_motion_vector(ivec2 texel_sample) +{ + /** + * Dilate velocity by using the nearest pixel in a cross pattern. + * "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 (Slide 27) + */ + const ivec2 corners[4] = ivec2[4](ivec2(-2, -2), ivec2(2, -2), ivec2(-2, 2), ivec2(2, 2)); + float min_depth = dof_fetch_half_depth(ivec2(0)); + ivec2 nearest_texel = ivec2(0); + for (int i = 0; i < 4; i++) { + float depth = dof_fetch_half_depth(corners[i]); + if (min_depth > depth) { + min_depth = depth; + nearest_texel = corners[i]; + } + } + /* Convert to full resolution buffer pixel. */ + ivec2 velocity_texel = (texel_sample + nearest_texel) * 2; + velocity_texel = clamp(velocity_texel, ivec2(0), textureSize(velocity_tx, 0).xy - 1); + vec4 vector = velocity_resolve(velocity_tx, velocity_texel, min_depth); + /* Transform to **half** pixel space. */ + return vector.xy * vec2(textureSize(color_tx, 0)); +} + +/* Load color using a special filter to avoid loosing detail. + * \a texel is sample position with subpixel accuracy. */ +DofSample dof_sample_history(vec2 input_texel) +{ +#if 1 /* Bilinar. */ + vec2 uv = vec2(input_texel + 0.5) / textureSize(in_history_tx, 0); + vec4 color = textureLod(in_history_tx, uv, 0.0); + +#else /* Catmull Rom interpolation. 5 Bilinear Taps. */ + vec2 center_texel; + vec2 inter_texel = modf(input_texel, center_texel); + vec2 weights[4]; + film_get_catmull_rom_weights(inter_texel, weights); + + /** + * Use optimized version by leveraging bilinear filtering from hardware sampler and by removing + * corner taps. + * From "Filmic SMAA" by Jorge Jimenez at Siggraph 2016 + * http://advances.realtimerendering.com/s2016/Filmic%20SMAA%20v7.pptx + */ + center_texel += 0.5; + + /* Slide 92. */ + vec2 weight_12 = weights[1] + weights[2]; + vec2 uv_12 = (center_texel + weights[2] / weight_12) * film_buf.extent_inv; + vec2 uv_0 = (center_texel - 1.0) * film_buf.extent_inv; + vec2 uv_3 = (center_texel + 2.0) * film_buf.extent_inv; + + vec4 color; + vec4 weight_cross = weight_12.xyyx * vec4(weights[0].yx, weights[3].xy); + float weight_center = weight_12.x * weight_12.y; + + color = textureLod(in_history_tx, uv_12, 0.0) * weight_center; + color += textureLod(in_history_tx, vec2(uv_12.x, uv_0.y), 0.0) * weight_cross.x; + color += textureLod(in_history_tx, vec2(uv_0.x, uv_12.y), 0.0) * weight_cross.y; + color += textureLod(in_history_tx, vec2(uv_3.x, uv_12.y), 0.0) * weight_cross.z; + color += textureLod(in_history_tx, vec2(uv_12.x, uv_3.y), 0.0) * weight_cross.w; + /* Re-normalize for the removed corners. */ + color /= (weight_center + sum(weight_cross)); +#endif + /* NOTE(fclem): Opacity is wrong on purpose. Final Opacity does not rely on history. */ + return DofSample(color.xyzz, color.w); +} + +/* Modulate the history color to avoid ghosting artifact. */ +DofSample dof_amend_history(DofNeighborhoodMinMax bbox, DofSample history, DofSample src) +{ +#if 0 + /* Clip instead of clamping to avoid color accumulating in the AABB corners. */ + vec3 clip_dir = src.color.rgb - history.color.rgb; + + float t = line_aabb_clipping_dist( + history.color.rgb, clip_dir, bbox.min.color.rgb, bbox.max.color.rgb); + history.color.rgb += clip_dir * saturate(t); +#else + /* More responsive. */ + history.color = clamp(history.color, bbox.min.color, bbox.max.color); +#endif + /* Clamp CoC to reduce convergence time. Otherwise the result is laggy. */ + history.coc = clamp(history.coc, bbox.min.coc, bbox.max.coc); + + return history; +} + +float dof_history_blend_factor( + float velocity, vec2 texel, DofNeighborhoodMinMax bbox, DofSample src, DofSample dst) +{ + float luma_min = bbox.min.color.x; + float luma_max = bbox.max.color.x; + float luma_incoming = src.color.x; + float luma_history = dst.color.x; + + /* 5% of incoming color by default. */ + float blend = 0.05; + /* Blend less history if the pixel has substential velocity. */ + /* NOTE(fclem): velocity threshold multiplied by 2 because of half resolution. */ + blend = mix(blend, 0.20, saturate(velocity * 0.02 * 2.0)); + /** + * "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 (Slide 43) + * Bias towards history if incomming pixel is near clamping. Reduces flicker. + */ + float distance_to_luma_clip = min_v2(vec2(luma_history - luma_min, luma_max - luma_history)); + /* Divide by bbox size to get a factor. 2 factor to compensate the line above. */ + distance_to_luma_clip *= 2.0 * safe_rcp(luma_max - luma_min); + /* Linearly blend when history gets bellow to 25% of the bbox size. */ + blend *= saturate(distance_to_luma_clip * 4.0 + 0.1); + /* Progressively discard history until history CoC is twice as big as the filtered CoC. + * Note we use absolute diff here because we are not comparing neighbors and thus do not risk to + * dilate thin features like hair (slide 19). */ + float coc_diff_ratio = saturate(abs(src.coc - dst.coc) / max(1.0, abs(src.coc))); + blend = mix(blend, 1.0, coc_diff_ratio); + /* Discard out of view history. */ + if (any(lessThan(texel, vec2(0))) || + any(greaterThanEqual(texel, vec2(imageSize(out_history_img))))) { + blend = 1.0; + } + /* Discard history if invalid. */ + if (use_history == false) { + blend = 1.0; + } + return blend; +} + +void main() +{ + dof_cache_init(); + + ivec2 src_texel = ivec2(gl_GlobalInvocationID.xy); + + /** + * Naming convention is taken from the film implementation. + * SRC is incoming new data. + * DST is history data. + */ + DofSample src = dof_spatial_filtering(); + + /* Reproject by finding where this pixel was in the previous frame. */ + vec2 motion = dof_pixel_history_motion_vector(src_texel); + vec2 history_texel = vec2(src_texel) + motion; + + float velocity = length(motion); + + DofSample dst = dof_sample_history(history_texel); + + /* Get local color bounding box of source neighboorhood. */ + DofNeighborhoodMinMax bbox = dof_neighbor_boundbox(); + + float blend = dof_history_blend_factor(velocity, history_texel, bbox, src, dst); + + dst = dof_amend_history(bbox, dst, src); + + /* Luma weighted blend to reduce flickering. */ + float weight_dst = dof_luma_weight(dst.color.x) * (1.0 - blend); + float weight_src = dof_luma_weight(src.color.x) * (blend); + + DofSample result; + /* Weighted blend. */ + result.color = vec4(dst.color.rgb, dst.coc) * weight_dst + + vec4(src.color.rgb, src.coc) * weight_src; + result.color /= weight_src + weight_dst; + + /* Save history for next iteration. Still in YCoCg space with CoC in alpha. */ + imageStore(out_history_img, src_texel, result.color); + + /* Un-swizzle. */ + result.coc = result.color.a; + /* Clamp opacity since we don't store it in history. */ + result.color.a = clamp(src.color.a, bbox.min.color.a, bbox.max.color.a); + + result.color = colorspace_scene_linear_from_YCoCg(result.color); + + imageStore(out_color_img, src_texel, result.color); + imageStore(out_coc_img, src_texel, vec4(result.coc)); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_dilate_comp.glsl new file mode 100644 index 00000000000..dba8b5fd79d --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_dilate_comp.glsl @@ -0,0 +1,97 @@ + +/** + * Tile dilate pass: Takes the 8x8 Tiles buffer and converts dilates the tiles with large CoC to + * their neighborhood. This pass is repeated multiple time until the maximum CoC can be covered. + * + * Input & Output: + * - Separated foreground and background CoC. 1/8th of half-res resolution. So 1/16th of full-res. + **/ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +/* Error introduced by the random offset of the gathering kernel's center. */ +const float bluring_radius_error = 1.0 + 1.0 / (float(DOF_GATHER_RING_COUNT) + 0.5); +const float tile_to_fullres_factor = float(DOF_TILES_SIZE * 2); + +void main() +{ + ivec2 center_tile_pos = ivec2(gl_GlobalInvocationID.xy); + + CocTile ring_buckets[DOF_DILATE_RING_COUNT]; + + for (int ring = 0; ring < ring_count && ring < DOF_DILATE_RING_COUNT; ring++) { + ring_buckets[ring] = dof_coc_tile_init(); + + int ring_distance = ring + 1; + for (int sample_id = 0; sample_id < 4 * ring_distance; sample_id++) { + ivec2 offset = dof_square_ring_sample_offset(ring_distance, sample_id); + + offset *= ring_width_multiplier; + + for (int i = 0; i < 2; i++) { + ivec2 adj_tile_pos = center_tile_pos + ((i == 0) ? offset : -offset); + + CocTile adj_tile = dof_coc_tile_load(in_tiles_fg_img, in_tiles_bg_img, adj_tile_pos); + + if (DILATE_MODE_MIN_MAX) { + /* Actually gather the "absolute" biggest coc but keeping the sign. */ + ring_buckets[ring].fg_min_coc = min(ring_buckets[ring].fg_min_coc, adj_tile.fg_min_coc); + ring_buckets[ring].bg_max_coc = max(ring_buckets[ring].bg_max_coc, adj_tile.bg_max_coc); + } + else { /* DILATE_MODE_MIN_ABS */ + ring_buckets[ring].fg_max_coc = max(ring_buckets[ring].fg_max_coc, adj_tile.fg_max_coc); + ring_buckets[ring].bg_min_coc = min(ring_buckets[ring].bg_min_coc, adj_tile.bg_min_coc); + + /* Should be tight as possible to reduce gather overhead (see slide 61). */ + float closest_neighbor_distance = length(max(abs(vec2(offset)) - 1.0, 0.0)) * + tile_to_fullres_factor; + + ring_buckets[ring].fg_max_intersectable_coc = max( + ring_buckets[ring].fg_max_intersectable_coc, + adj_tile.fg_max_intersectable_coc + closest_neighbor_distance); + ring_buckets[ring].bg_min_intersectable_coc = min( + ring_buckets[ring].bg_min_intersectable_coc, + adj_tile.bg_min_intersectable_coc + closest_neighbor_distance); + } + } + } + } + + /* Load center tile. */ + CocTile out_tile = dof_coc_tile_load(in_tiles_fg_img, in_tiles_bg_img, center_tile_pos); + + for (int ring = 0; ring < ring_count && ring < DOF_DILATE_RING_COUNT; ring++) { + float ring_distance = float(ring + 1); + + ring_distance = (ring_distance * ring_width_multiplier - 1) * tile_to_fullres_factor; + + if (DILATE_MODE_MIN_MAX) { + /* NOTE(fclem): Unsure if both sides of the inequalities have the same unit. */ + if (-ring_buckets[ring].fg_min_coc * bluring_radius_error > ring_distance) { + out_tile.fg_min_coc = min(out_tile.fg_min_coc, ring_buckets[ring].fg_min_coc); + } + + if (ring_buckets[ring].bg_max_coc * bluring_radius_error > ring_distance) { + out_tile.bg_max_coc = max(out_tile.bg_max_coc, ring_buckets[ring].bg_max_coc); + } + } + else { /* DILATE_MODE_MIN_ABS */ + /* Find minimum absolute CoC radii that will be intersected for the previously + * computed maximum CoC values. */ + if (-out_tile.fg_min_coc * bluring_radius_error > ring_distance) { + out_tile.fg_max_coc = max(out_tile.fg_max_coc, ring_buckets[ring].fg_max_coc); + out_tile.fg_max_intersectable_coc = max(out_tile.fg_max_intersectable_coc, + ring_buckets[ring].fg_max_intersectable_coc); + } + + if (out_tile.bg_max_coc * bluring_radius_error > ring_distance) { + out_tile.bg_min_coc = min(out_tile.bg_min_coc, ring_buckets[ring].bg_min_coc); + out_tile.bg_min_intersectable_coc = min(out_tile.bg_min_intersectable_coc, + ring_buckets[ring].bg_min_intersectable_coc); + } + } + } + + ivec2 texel_out = ivec2(gl_GlobalInvocationID.xy); + dof_coc_tile_store(out_tiles_fg_img, out_tiles_bg_img, texel_out, out_tile); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl new file mode 100644 index 00000000000..88737ade386 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl @@ -0,0 +1,78 @@ + +/** + * Tile flatten pass: Takes the halfres CoC buffer and converts it to 8x8 tiles. + * + * Output min and max values for each tile and for both foreground & background. + * Also outputs min intersectable CoC for the background, which is the minimum CoC + * that comes from the background pixels. + * + * Input: + * - Half-resolution Circle of confusion. Out of setup pass. + * Output: + * - Separated foreground and background CoC. 1/8th of half-res resolution. So 1/16th of full-res. + */ + +#pragma BLENDER_REQUIRE(eevee_depth_of_field_lib.glsl) + +/** + * In order to use atomic operations, we have to use uints. But this means having to deal with the + * negative number ourselves. Luckily, each ground have a nicely defined range of values we can + * remap to positive float. + */ +shared uint fg_min_coc; +shared uint fg_max_coc; +shared uint fg_max_intersectable_coc; +shared uint bg_min_coc; +shared uint bg_max_coc; +shared uint bg_min_intersectable_coc; + +const uint dof_tile_large_coc_uint = floatBitsToUint(dof_tile_large_coc); + +void main() +{ + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + /* NOTE: Min/Max flipped because of inverted fg_coc sign. */ + fg_min_coc = floatBitsToUint(0.0); + fg_max_coc = dof_tile_large_coc_uint; + fg_max_intersectable_coc = dof_tile_large_coc_uint; + bg_min_coc = dof_tile_large_coc_uint; + bg_max_coc = floatBitsToUint(0.0); + bg_min_intersectable_coc = dof_tile_large_coc_uint; + } + barrier(); + + ivec2 sample_texel = min(ivec2(gl_GlobalInvocationID.xy), textureSize(coc_tx, 0).xy - 1); + vec2 sample_data = texelFetch(coc_tx, sample_texel, 0).rg; + + float sample_coc = sample_data.x; + uint fg_coc = floatBitsToUint(max(-sample_coc, 0.0)); + /* NOTE: atomicMin/Max flipped because of inverted fg_coc sign. */ + atomicMax(fg_min_coc, fg_coc); + atomicMin(fg_max_coc, fg_coc); + atomicMin(fg_max_intersectable_coc, (sample_coc < 0.0) ? fg_coc : dof_tile_large_coc_uint); + + uint bg_coc = floatBitsToUint(max(sample_coc, 0.0)); + atomicMin(bg_min_coc, bg_coc); + atomicMax(bg_max_coc, bg_coc); + atomicMin(bg_min_intersectable_coc, (sample_coc > 0.0) ? bg_coc : dof_tile_large_coc_uint); + + barrier(); + + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + if (fg_max_intersectable_coc == dof_tile_large_coc_uint) { + fg_max_intersectable_coc = floatBitsToUint(0.0); + } + + CocTile tile; + /* Foreground sign is flipped since we compare unsigned representation. */ + tile.fg_min_coc = -uintBitsToFloat(fg_min_coc); + tile.fg_max_coc = -uintBitsToFloat(fg_max_coc); + tile.fg_max_intersectable_coc = -uintBitsToFloat(fg_max_intersectable_coc); + tile.bg_min_coc = uintBitsToFloat(bg_min_coc); + tile.bg_max_coc = uintBitsToFloat(bg_max_coc); + tile.bg_min_intersectable_coc = uintBitsToFloat(bg_min_intersectable_coc); + + ivec2 tile_co = ivec2(gl_WorkGroupID.xy); + dof_coc_tile_store(out_tiles_fg_img, out_tiles_bg_img, tile_co, tile); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl index b286836e8df..bf6293d5561 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl @@ -7,6 +7,7 @@ #pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) #pragma BLENDER_REQUIRE(eevee_camera_lib.glsl) #pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl) /* Return scene linear Z depth from the camera or radial depth for panoramic cameras. */ float film_depth_convert_to_scene(float depth) @@ -18,32 +19,6 @@ float film_depth_convert_to_scene(float depth) return abs(get_view_z_from_depth(depth)); } -vec3 film_YCoCg_from_scene_linear(vec3 rgb_color) -{ - const mat3 colorspace_tx = transpose(mat3(vec3(1, 2, 1), /* Y */ - vec3(2, 0, -2), /* Co */ - vec3(-1, 2, -1))); /* Cg */ - return colorspace_tx * rgb_color; -} - -vec4 film_YCoCg_from_scene_linear(vec4 rgba_color) -{ - return vec4(film_YCoCg_from_scene_linear(rgba_color.rgb), rgba_color.a); -} - -vec3 film_scene_linear_from_YCoCg(vec3 ycocg_color) -{ - float Y = ycocg_color.x; - float Co = ycocg_color.y; - float Cg = ycocg_color.z; - - vec3 rgb_color; - rgb_color.r = Y + Co - Cg; - rgb_color.g = Y + Cg; - rgb_color.b = Y - Co - Cg; - return rgb_color * 0.25; -} - /* Load a texture sample in a specific format. Combined pass needs to use this. */ vec4 film_texelfetch_as_YCoCg_opacity(sampler2D tx, ivec2 texel) { @@ -51,7 +26,7 @@ vec4 film_texelfetch_as_YCoCg_opacity(sampler2D tx, ivec2 texel) /* Convert transmittance to opacity. */ color.a = saturate(1.0 - color.a); /* Transform to YCoCg for accumulation. */ - color.rgb = film_YCoCg_from_scene_linear(color.rgb); + color.rgb = colorspace_YCoCg_from_scene_linear(color.rgb); return color; } @@ -220,7 +195,7 @@ vec2 film_pixel_history_motion_vector(ivec2 texel_sample) float min_depth = texelFetch(depth_tx, texel_sample, 0).x; ivec2 nearest_texel = texel_sample; for (int i = 0; i < 4; i++) { - ivec2 texel = clamp(texel_sample + corners[i], ivec2(0), textureSize(depth_tx, 0).xy); + ivec2 texel = clamp(texel_sample + corners[i], ivec2(0), textureSize(depth_tx, 0).xy - 1); float depth = texelFetch(depth_tx, texel, 0).x; if (min_depth > depth) { min_depth = depth; @@ -254,7 +229,7 @@ void film_get_catmull_rom_weights(vec2 t, out vec2 weights[4]) weights[3] = fct3 - fct2; } -/* Load color using a special filter to avoid loosing detail. +/* Load color using a special filter to avoid losing detail. * \a texel is sample position with subpixel accuracy. */ vec4 film_sample_catmull_rom(sampler2D color_tx, vec2 input_texel) { @@ -390,7 +365,7 @@ vec4 film_amend_combined_history( float t = line_aabb_clipping_dist(color_history.rgb, clip_dir.rgb, min_color.rgb, max_color.rgb); color_history.rgb += clip_dir.rgb * saturate(t); - /* Clip alpha on its own to avoid interference with other chanels. */ + /* Clip alpha on its own to avoid interference with other channels. */ float t_a = film_aabb_clipping_dist_alpha(color_history.a, clip_dir.a, min_color.a, max_color.a); color_history.a += clip_dir.a * saturate(t_a); @@ -406,16 +381,16 @@ float film_history_blend_factor(float velocity, { /* 5% of incoming color by default. */ float blend = 0.05; - /* Blend less history if the pixel has substential velocity. */ + /* Blend less history if the pixel has substantial velocity. */ blend = mix(blend, 0.20, saturate(velocity * 0.02)); /** * "High Quality Temporal Supersampling" by Brian Karis at Siggraph 2014 (Slide 43) - * Bias towards history if incomming pixel is near clamping. Reduces flicker. + * Bias towards history if incoming pixel is near clamping. Reduces flicker. */ float distance_to_luma_clip = min_v2(vec2(luma_history - luma_min, luma_max - luma_history)); /* Divide by bbox size to get a factor. 2 factor to compensate the line above. */ distance_to_luma_clip *= 2.0 * safe_rcp(luma_max - luma_min); - /* Linearly blend when history gets bellow to 25% of the bbox size. */ + /* Linearly blend when history gets below to 25% of the bbox size. */ blend *= saturate(distance_to_luma_clip * 4.0 + 0.1); /* Discard out of view history. */ if (any(lessThan(texel, vec2(0))) || any(greaterThanEqual(texel, film_buf.extent))) { @@ -451,13 +426,13 @@ void film_store_combined( float velocity = length(motion); - /* Load weight if it is not uniform accross the whole buffer (i.e: upsampling, panoramic). */ + /* Load weight if it is not uniform across the whole buffer (i.e: upsampling, panoramic). */ // dst.weight = film_weight_load(texel_combined); color_dst = film_sample_catmull_rom(in_combined_tx, history_texel); - color_dst.rgb = film_YCoCg_from_scene_linear(color_dst.rgb); + color_dst.rgb = colorspace_YCoCg_from_scene_linear(color_dst.rgb); - /* Get local color bounding box of source neighboorhood. */ + /* Get local color bounding box of source neighborhood. */ vec4 min_color, max_color; film_combined_neighbor_boundbox(src_texel, min_color, max_color); @@ -473,7 +448,7 @@ void film_store_combined( else { /* Everything is static. Use render accumulation. */ color_dst = texelFetch(in_combined_tx, dst.texel, 0); - color_dst.rgb = film_YCoCg_from_scene_linear(color_dst.rgb); + color_dst.rgb = colorspace_YCoCg_from_scene_linear(color_dst.rgb); /* Luma weighted blend to avoid flickering. */ weight_dst = film_luma_weight(color_dst.x) * dst.weight; @@ -483,7 +458,7 @@ void film_store_combined( color = color_dst * weight_dst + color_src * weight_src; color /= weight_src + weight_dst; - color.rgb = film_scene_linear_from_YCoCg(color.rgb); + color.rgb = colorspace_scene_linear_from_YCoCg(color.rgb); /* Fix alpha not accumulating to 1 because of float imprecision. */ if (color.a > 0.995) { @@ -622,7 +597,7 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth src = film_sample_get(i, texel_film); film_sample_accum_combined(src, combined_accum, weight_accum); } - /* NOTE: src.texel is center texel in incomming data buffer. */ + /* NOTE: src.texel is center texel in incoming data buffer. */ film_store_combined(dst, src.texel, combined_accum, weight_accum, out_color); } @@ -636,6 +611,8 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth vec4 normal = texelFetch(normal_tx, film_sample.texel, 0); float depth = texelFetch(depth_tx, film_sample.texel, 0).x; vec4 vector = velocity_resolve(vector_tx, film_sample.texel, depth); + /* Transform to pixel space. */ + vector *= vec4(film_buf.render_extent, -film_buf.render_extent); film_store_depth(texel_film, depth, out_depth); film_store_data(texel_film, film_buf.normal_id, normal, out_color); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl new file mode 100644 index 00000000000..99186ab6f67 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl @@ -0,0 +1,116 @@ + +/** + * Dilate motion vector tiles until we covered maximum velocity. + * Outputs the largest intersecting motion vector in the neighborhood. + * + */ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl) + +#define DEBUG_BYPASS_DILATION 0 + +struct MotionRect { + ivec2 bottom_left; + ivec2 extent; +}; + +MotionRect compute_motion_rect(ivec2 tile, vec2 motion) +{ +#if DEBUG_BYPASS_DILATION + return MotionRect(tile, ivec2(1)); +#endif + /* Ceil to number of tile touched.*/ + ivec2 point1 = tile + ivec2(sign(motion) * ceil(abs(motion) / float(MOTION_BLUR_TILE_SIZE))); + ivec2 point2 = tile; + + ivec2 max_point = max(point1, point2); + ivec2 min_point = min(point1, point2); + /* Clamp to bounds. */ + max_point = min(max_point, imageSize(in_tiles_img) - 1); + min_point = max(min_point, ivec2(0)); + + MotionRect rect; + rect.bottom_left = min_point; + rect.extent = 1 + max_point - min_point; + return rect; +} + +struct MotionLine { + /** Origin of the line. */ + vec2 origin; + /** Normal to the line direction. */ + vec2 normal; +}; + +MotionLine compute_motion_line(ivec2 tile, vec2 motion) +{ + vec2 dir = safe_normalize(motion); + + MotionLine line; + line.origin = vec2(tile); + /* Rotate 90° Counter-Clockwise. */ + line.normal = vec2(-dir.y, dir.x); + return line; +} + +bool is_inside_motion_line(ivec2 tile, MotionLine motion_line) +{ +#if DEBUG_BYPASS_DILATION + return true; +#endif + /* NOTE: Everything in is tile unit. */ + float dist = point_line_projection_dist(vec2(tile), motion_line.origin, motion_line.normal); + /* In order to be conservative and for simplicity, we use the tiles bounding circles. + * Consider that both the tile and the line have bounding radius of M_SQRT1_2. */ + return abs(dist) < M_SQRT2; +} + +void main() +{ + ivec2 src_tile = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(src_tile, imageSize(in_tiles_img)))) { + return; + } + + vec4 max_motion = imageLoad(in_tiles_img, src_tile); + + MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile); + MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + if (true) { + /* Rectangular area (in tiles) where the motion vector spreads. */ + MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy); + MotionLine motion_line = compute_motion_line(src_tile, max_motion.xy); + /* Do a conservative rasterization of the line of the motion vector line. */ + for (int x = 0; x < motion_rect.extent.x; x++) { + for (int y = 0; y < motion_rect.extent.y; y++) { + ivec2 tile = motion_rect.bottom_left + ivec2(x, y); + if (is_inside_motion_line(tile, motion_line)) { + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in + * the motion next so that weighting in gather pass is better. */ + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + } + } + } + } + + if (true) { + MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + /* Rectangular area (in tiles) where the motion vector spreads. */ + MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw); + MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw); + /* Do a conservative rasterization of the line of the motion vector line. */ + for (int x = 0; x < motion_rect.extent.x; x++) { + for (int y = 0; y < motion_rect.extent.y; y++) { + ivec2 tile = motion_rect.bottom_left + ivec2(x, y); + if (is_inside_motion_line(tile, motion_line)) { + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in + * the motion next so that weighting in gather pass is better. */ + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + } + } + } + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl new file mode 100644 index 00000000000..cbbeea25d20 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl @@ -0,0 +1,103 @@ + +/** + * Shaders that down-sample velocity buffer into squared tile of MB_TILE_DIVISOR pixels wide. + * Outputs the largest motion vector in the tile area. + * Also perform velocity resolve to speedup the convolution pass. + * + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * Adapted from G3D Innovation Engine implementation. + */ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) + +shared uint payload_prev; +shared uint payload_next; +shared vec2 max_motion_prev; +shared vec2 max_motion_next; + +/* Store velocity magnitude in the MSB and thread id in the LSB. */ +uint pack_payload(vec2 motion, uvec2 thread_id) +{ + /* NOTE: We clamp max velocity to 16k pixels. */ + return (min(uint(ceil(length(motion))), 0xFFFFu) << 16u) | (thread_id.y << 8) | thread_id.x; +} + +/* Return thread index from the payload. */ +uvec2 unpack_payload(uint payload) +{ + return uvec2(payload & 0xFFu, (payload >> 8) & 0xFFu); +} + +void main() +{ + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + payload_prev = 0u; + payload_next = 0u; + } + barrier(); + + uint local_payload_prev = 0u; + uint local_payload_next = 0u; + vec2 local_max_motion_prev; + vec2 local_max_motion_next; + + ivec2 texel = min(ivec2(gl_GlobalInvocationID.xy), imageSize(velocity_img) - 1); + + vec2 render_size = vec2(imageSize(velocity_img).xy); + vec2 uv = (vec2(texel) + 0.5) / render_size; + float depth = texelFetch(depth_tx, texel, 0).r; + vec4 motion = velocity_resolve(imageLoad(velocity_img, texel), uv, depth); +#ifdef FLATTEN_VIEWPORT + /* imageLoad does not perform the swizzling like sampler does. Do it manually. */ + motion = motion.xyxy; +#endif + + /* Store resolved velocity to speedup the gather pass. Out of bounds writes are ignored. + * Unfortunately, we cannot convert to pixel space here since it is also used by TAA and the + * motion blur needs to remain optional. */ + imageStore(velocity_img, ivec2(gl_GlobalInvocationID.xy), velocity_pack(motion)); + /* Clip velocity to viewport bounds (in NDC space). */ + vec2 line_clip; + line_clip.x = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, motion.xy * 2.0); + line_clip.y = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, -motion.zw * 2.0); + motion *= min(line_clip, vec2(1.0)).xxyy; + /* Convert to pixel space. Note this is only for velocity tiles. */ + motion *= render_size.xyxy; + /* Rescale to shutter relative motion for viewport. */ + motion *= motion_blur_buf.motion_scale.xxyy; + + uint sample_payload_prev = pack_payload(motion.xy, gl_LocalInvocationID.xy); + if (local_payload_prev < sample_payload_prev) { + local_payload_prev = sample_payload_prev; + local_max_motion_prev = motion.xy; + } + + uint sample_payload_next = pack_payload(motion.zw, gl_LocalInvocationID.xy); + if (local_payload_next < sample_payload_next) { + local_payload_next = sample_payload_next; + local_max_motion_next = motion.zw; + } + + /* Compare the local payload with the other threads. */ + atomicMax(payload_prev, local_payload_prev); + atomicMax(payload_next, local_payload_next); + barrier(); + + /* Need to broadcast the result to another thread in order to issue a unique write. */ + if (all(equal(unpack_payload(payload_prev), gl_LocalInvocationID.xy))) { + max_motion_prev = local_max_motion_prev; + } + if (all(equal(unpack_payload(payload_next), gl_LocalInvocationID.xy))) { + max_motion_next = local_max_motion_next; + } + barrier(); + + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + ivec2 tile_co = ivec2(gl_WorkGroupID.xy); + imageStore(out_tiles_img, tile_co, vec4(max_motion_prev, max_motion_next)); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl new file mode 100644 index 00000000000..5249e6637b6 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl @@ -0,0 +1,221 @@ + +/** + * Perform two gather blur in the 2 motion blur directions + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * With modification from the presentation: + * Next Generation Post Processing in Call of Duty Advanced Warfare + * by Jorge Jimenez + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl) + +const int gather_sample_count = 8; + +/* Converts uv velocity into pixel space. Assumes velocity_tx is the same resolution as the + * target post-fx framebuffer. */ +vec4 motion_blur_sample_velocity(sampler2D velocity_tx, vec2 uv) +{ + /* We can load velocity without velocity_resolve() since we resolved during the flatten pass. */ + vec4 velocity = velocity_unpack(texture(velocity_tx, uv)); + return velocity * vec2(textureSize(velocity_tx, 0)).xyxy * motion_blur_buf.motion_scale.xxyy; +} + +vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length) +{ + return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0); +} + +vec2 depth_compare(float center_depth, float sample_depth) +{ + vec2 depth_scale = vec2(-motion_blur_buf.depth_scale, motion_blur_buf.depth_scale); + return saturate(0.5 + depth_scale * (sample_depth - center_depth)); +} + +/* Kill contribution if not going the same direction. */ +float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length) +{ + if (sample_motion_length < 0.5) { + return 1.0; + } + return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0; +} + +/* Return background (x) and foreground (y) weights. */ +vec2 sample_weights(float center_depth, + float sample_depth, + float center_motion_length, + float sample_motion_length, + float offset_length) +{ + /* Classify foreground/background. */ + vec2 depth_weight = depth_compare(center_depth, sample_depth); + /* Weight if sample is overlapping or under the center pixel. */ + vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length); + return depth_weight * spread_weight; +} + +struct Accumulator { + vec4 fg; + vec4 bg; + /** x: Background, y: Foreground, z: dir. */ + vec3 weight; +}; + +void gather_sample(vec2 screen_uv, + float center_depth, + float center_motion_len, + vec2 offset, + float offset_len, + const bool next, + inout Accumulator accum) +{ + vec2 sample_uv = screen_uv - offset * motion_blur_buf.target_size_inv; + vec4 sample_vectors = motion_blur_sample_velocity(velocity_tx, sample_uv); + vec2 sample_motion = (next) ? sample_vectors.zw : sample_vectors.xy; + float sample_motion_len = length(sample_motion); + float sample_depth = texture(depth_tx, sample_uv).r; + vec4 sample_color = textureLod(in_color_tx, sample_uv, 0.0); + + sample_depth = get_view_z_from_depth(sample_depth); + + vec3 weights; + weights.xy = sample_weights( + center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len); + weights.z = dir_compare(offset, sample_motion, sample_motion_len); + weights.xy *= weights.z; + + accum.fg += sample_color * weights.y; + accum.bg += sample_color * weights.x; + accum.weight += weights; +} + +void gather_blur(vec2 screen_uv, + vec2 center_motion, + float center_depth, + vec2 max_motion, + float ofs, + const bool next, + inout Accumulator accum) +{ + float center_motion_len = length(center_motion); + float max_motion_len = length(max_motion); + + /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel. + * Fix this by overriding the max_motion. */ + if (max_motion_len < center_motion_len) { + max_motion_len = center_motion_len; + max_motion = center_motion; + } + + if (max_motion_len < 0.5) { + return; + } + + int i; + float t, inc = 1.0 / float(gather_sample_count); + for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) { + gather_sample(screen_uv, + center_depth, + center_motion_len, + max_motion * t, + max_motion_len * t, + next, + accum); + } + + if (center_motion_len < 0.5) { + return; + } + + for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) { + /* Also sample in center motion direction. + * Allow recovering motion where there is conflicting + * motion between foreground and background. */ + gather_sample(screen_uv, + center_depth, + center_motion_len, + center_motion * t, + center_motion_len * t, + next, + accum); + } +} + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(depth_tx, 0).xy); + + if (!in_texture_range(texel, depth_tx)) { + return; + } + + /* Data of the center pixel of the gather (target). */ + float center_depth = get_view_z_from_depth(texelFetch(depth_tx, texel, 0).r); + vec4 center_motion = motion_blur_sample_velocity(velocity_tx, uv); + + vec4 center_color = textureLod(in_color_tx, uv, 0.0); + + float noise_offset = sampling_rng_1D_get(SAMPLING_TIME); + /** TODO(fclem) Blue noise. */ + vec2 rand = vec2(interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 0, noise_offset), + interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 1, noise_offset)); + + /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. + * Note this randomize only in one direction but in practice it's enough. */ + rand.x = rand.x * 2.0 - 1.0; + ivec2 tile = (texel + ivec2(rand.x * float(MOTION_BLUR_TILE_SIZE) * 0.25)) / + MOTION_BLUR_TILE_SIZE; + tile = clamp(tile, ivec2(0), imageSize(in_tiles_img) - 1); + /* NOTE: Tile velocity is already in pixel space and with correct zw sign. */ + vec4 max_motion; + /* Load dilation result from the indirection table. */ + ivec2 tile_prev; + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev); + max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy; + ivec2 tile_next; + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next); + max_motion.zw = imageLoad(in_tiles_img, tile_next).zw; + + Accumulator accum; + accum.weight = vec3(0.0, 0.0, 1.0); + accum.bg = vec4(0.0); + accum.fg = vec4(0.0); + /* First linear gather. time = [T - delta, T] */ + gather_blur(uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum); + /* Second linear gather. time = [T, T + delta] */ + gather_blur(uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum); + +#if 1 /* Own addition. Not present in reference implementation. */ + /* Avoid division by 0.0. */ + float w = 1.0 / (50.0 * float(gather_sample_count) * 4.0); + accum.bg += center_color * w; + accum.weight.x += w; + /* NOTE: In Jimenez's presentation, they used center sample. + * We use background color as it contains more information for foreground + * elements that have not enough weights. + * Yield better blur in complex motion. */ + center_color = accum.bg / accum.weight.x; +#endif + /* Merge background. */ + accum.fg += accum.bg; + accum.weight.y += accum.weight.x; + /* Balance accumulation for failed samples. + * We replace the missing foreground by the background. */ + float blend_fac = saturate(1.0 - accum.weight.y / accum.weight.z); + vec4 out_color = (accum.fg / accum.weight.z) + center_color * blend_fac; + +#if 0 /* For debugging. */ + out_color.rgb = out_color.ggg; + out_color.rg += max_motion.xy; +#endif + + imageStore(out_color_img, texel, out_color); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl new file mode 100644 index 00000000000..436fd01795a --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl @@ -0,0 +1,48 @@ + + +/* -------------------------------------------------------------------- */ +/** \name Tile indirection packing + * \{ */ + +#define MotionPayload uint + +/* Store velocity magnitude in the MSB to be able to use it with atomicMax operations. */ +MotionPayload motion_blur_tile_indirection_pack_payload(vec2 motion, uvec2 payload) +{ + /* NOTE: Clamp to 16383 pixel velocity. After that, it is tile position that determine the tile + * to dilate over. */ + uint velocity = min(uint(ceil(length(motion))), 0x3FFFu); + /* Designed for 512x512 tiles max. */ + return (velocity << 18u) | ((payload.x & 0x1FFu) << 9u) | (payload.y & 0x1FFu); +} + +/* Return thread index. */ +ivec2 motion_blur_tile_indirection_pack_payload(uint data) +{ + return ivec2((data >> 9u) & 0x1FFu, data & 0x1FFu); +} + +uint motion_blur_tile_indirection_index(uint motion_step, uvec2 tile) +{ + uint index = tile.x; + index += tile.y * MOTION_BLUR_MAX_TILE; + index += motion_step * MOTION_BLUR_MAX_TILE * MOTION_BLUR_MAX_TILE; + return index; +} + +#define MOTION_PREV 0u +#define MOTION_NEXT 1u + +#define motion_blur_tile_indirection_store(table_, step_, tile, payload_) \ + if (true) { \ + uint index = motion_blur_tile_indirection_index(step_, tile); \ + atomicMax(table_[index], payload_); \ + } + +#define motion_blur_tile_indirection_load(table_, step_, tile_, result_) \ + if (true) { \ + uint index = motion_blur_tile_indirection_index(step_, tile_); \ + result_ = motion_blur_tile_indirection_pack_payload(table_[index]); \ + } + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl new file mode 100644 index 00000000000..0eea4a5ff33 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl @@ -0,0 +1,104 @@ + +/** + * Sampling data accessors and random number generators. + * Also contains some sample mapping functions. + **/ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Sampling data. + * + * Return a random values from Low Discrepancy Sequence in [0..1) range. + * This value is uniform (constant) for the whole scene sample. + * You might want to couple it with a noise function. + * \{ */ + +#ifdef EEVEE_SAMPLING_DATA + +float sampling_rng_1D_get(const eSamplingDimension dimension) +{ + return sampling_buf.dimensions[dimension]; +} + +vec2 sampling_rng_2D_get(const eSamplingDimension dimension) +{ + return vec2(sampling_buf.dimensions[dimension], sampling_buf.dimensions[dimension + 1u]); +} + +vec3 sampling_rng_3D_get(const eSamplingDimension dimension) +{ + return vec3(sampling_buf.dimensions[dimension], + sampling_buf.dimensions[dimension + 1u], + sampling_buf.dimensions[dimension + 2u]); +} + +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Random Number Generators. + * \{ */ + +/* Interlieved gradient noise by Jorge Jimenez + * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare + * Seeding found by Epic Game. */ +float interlieved_gradient_noise(vec2 pixel, float seed, float offset) +{ + pixel += seed * (vec2(47, 17) * 0.695); + return fract(offset + 52.9829189 * fract(0.06711056 * pixel.x + 0.00583715 * pixel.y)); +} + +/* From: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */ +float van_der_corput_radical_inverse(uint bits) +{ +#if 0 /* Reference */ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); +#else + bits = bitfieldReverse(bits); +#endif + /* Same as dividing by 0x100000000. */ + return float(bits) * 2.3283064365386963e-10; +} + +vec2 hammersley_2d(float i, float sample_count) +{ + vec2 rand; + rand.x = i / sample_count; + rand.y = van_der_corput_radical_inverse(uint(i)); + return rand; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Distribution mapping. + * + * Functions mapping input random numbers to sampling shapes (i.e: hemisphere). + * \{ */ + +/* Given 2 random number in [0..1] range, return a random unit disk sample. */ +vec2 sample_disk(vec2 noise) +{ + float angle = noise.x * M_2PI; + return vec2(cos(angle), sin(angle)) * sqrt(noise.y); +} + +/* This transform a 2d random sample (in [0..1] range) to a sample located on a cylinder of the + * same range. This is because the sampling functions expect such a random sample which is + * normally precomputed. */ +vec3 sample_cylinder(vec2 rand) +{ + float theta = rand.x; + float phi = (rand.y - 0.5) * M_2PI; + float cos_phi = cos(phi); + float sin_phi = sqrt(1.0 - sqr(cos_phi)) * sign(phi); + return vec3(theta, cos_phi, sin_phi); +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl index 34ea288852a..bd32215ddc2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl @@ -73,7 +73,7 @@ void main() nodetree_surface(); - // float noise_offset = sampling_rng_1D_get(sampling_buf, SAMPLING_TRANSPARENCY); + // float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY); float noise_offset = 0.5; float random_threshold = hashed_alpha_threshold(1.0, noise_offset, g_data.P); @@ -84,7 +84,7 @@ void main() #endif #ifdef MAT_VELOCITY - out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P - motion.next); + out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P + motion.next); out_velocity = velocity_pack(out_velocity); #endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl index c21456b7a5c..8d02609fedc 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl @@ -2,8 +2,6 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(eevee_camera_lib.glsl) -#ifdef VELOCITY_CAMERA - vec4 velocity_pack(vec4 data) { return data * 0.01; @@ -14,6 +12,8 @@ vec4 velocity_unpack(vec4 data) return data * 100.0; } +#ifdef VELOCITY_CAMERA + /** * Given a triple of position, compute the previous and next motion vectors. * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy). @@ -24,7 +24,15 @@ vec4 velocity_surface(vec3 P_prv, vec3 P, vec3 P_nxt) vec2 prev_uv = project_point(camera_prev.persmat, P_prv).xy; vec2 curr_uv = project_point(camera_curr.persmat, P).xy; vec2 next_uv = project_point(camera_next.persmat, P_nxt).xy; - + /* Fix issue with perspective division. */ + if (any(isnan(prev_uv))) { + prev_uv = curr_uv; + } + if (any(isnan(next_uv))) { + next_uv = curr_uv; + } + /* NOTE: We output both vectors in the same direction so we can reuse the same vector + * with rgrg swizzle in viewport. */ vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv); /* Convert NDC velocity to UV velocity */ motion *= 0.5; @@ -39,13 +47,14 @@ vec4 velocity_surface(vec3 P_prv, vec3 P, vec3 P_nxt) */ vec4 velocity_background(vec3 vV) { - /* Only transform direction to avoid loosing precision. */ + /* Only transform direction to avoid losing precision. */ vec3 V = transform_direction(camera_curr.viewinv, vV); /* NOTE: We don't use the drw_view.winmat to avoid adding the TAA jitter to the velocity. */ vec2 prev_uv = project_point(camera_prev.winmat, V).xy; vec2 curr_uv = project_point(camera_curr.winmat, V).xy; vec2 next_uv = project_point(camera_next.winmat, V).xy; - + /* NOTE: We output both vectors in the same direction so we can reuse the same vector + * with rgrg swizzle in viewport. */ vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv); /* Convert NDC velocity to UV velocity */ motion *= 0.5; @@ -53,15 +62,8 @@ vec4 velocity_background(vec3 vV) return motion; } -/** - * Load and resolve correct velocity as some pixels might still not have correct - * motion data for performance reasons. - */ -vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) +vec4 velocity_resolve(vec4 vector, vec2 uv, float depth) { - vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy); - vec4 vector = texelFetch(vector_tx, texel, 0); - if (vector.x == VELOCITY_INVALID) { bool is_background = (depth == 1.0); if (is_background) { @@ -78,6 +80,18 @@ vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) return velocity_unpack(vector); } +/** + * Load and resolve correct velocity as some pixels might still not have correct + * motion data for performance reasons. + * Returns motion vector in render UV space. + */ +vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) +{ + vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy); + vec4 vector = texelFetch(vector_tx, texel, 0); + return velocity_resolve(vector, uv, depth); +} + #endif #ifdef MAT_VELOCITY diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh new file mode 100644 index 00000000000..b398a6cc4e7 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +/* -------------------------------------------------------------------- */ +/** \name Setup + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_bokeh_lut) + .do_static_compilation(true) + .local_group_size(DOF_BOKEH_LUT_SIZE, DOF_BOKEH_LUT_SIZE) + .additional_info("eevee_shared", "draw_view") + .uniform_buf(1, "DepthOfFieldData", "dof_buf") + .image(0, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_gather_lut_img") + .image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_scatter_lut_img") + .image(2, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_resolve_lut_img") + .compute_source("eevee_depth_of_field_bokeh_lut_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_setup) + .do_static_compilation(true) + .local_group_size(DOF_DEFAULT_GROUP_SIZE, DOF_DEFAULT_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view") + .uniform_buf(1, "DepthOfFieldData", "dof_buf") + .sampler(0, ImageType::FLOAT_2D, "color_tx") + .sampler(1, ImageType::DEPTH_2D, "depth_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_coc_img") + .compute_source("eevee_depth_of_field_setup_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_stabilize) + .do_static_compilation(true) + .local_group_size(DOF_STABILIZE_GROUP_SIZE, DOF_STABILIZE_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view", "eevee_velocity_camera") + .uniform_buf(4, "DepthOfFieldData", "dof_buf") + .sampler(0, ImageType::FLOAT_2D, "coc_tx") + .sampler(1, ImageType::FLOAT_2D, "color_tx") + .sampler(2, ImageType::FLOAT_2D, "velocity_tx") + .sampler(3, ImageType::FLOAT_2D, "in_history_tx") + .sampler(4, ImageType::DEPTH_2D, "depth_tx") + .push_constant(Type::BOOL, "use_history") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_coc_img") + .image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_history_img") + .compute_source("eevee_depth_of_field_stabilize_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_downsample) + .do_static_compilation(true) + .local_group_size(DOF_DEFAULT_GROUP_SIZE, DOF_DEFAULT_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view") + .sampler(0, ImageType::FLOAT_2D, "color_tx") + .sampler(1, ImageType::FLOAT_2D, "coc_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .compute_source("eevee_depth_of_field_downsample_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_reduce) + .do_static_compilation(true) + .local_group_size(DOF_REDUCE_GROUP_SIZE, DOF_REDUCE_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view") + .uniform_buf(1, "DepthOfFieldData", "dof_buf") + .sampler(0, ImageType::FLOAT_2D, "downsample_tx") + .storage_buf(0, Qualifier::WRITE, "ScatterRect", "scatter_fg_list_buf[]") + .storage_buf(1, Qualifier::WRITE, "ScatterRect", "scatter_bg_list_buf[]") + .storage_buf(2, Qualifier::READ_WRITE, "DrawCommand", "scatter_fg_indirect_buf") + .storage_buf(3, Qualifier::READ_WRITE, "DrawCommand", "scatter_bg_indirect_buf") + .image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "inout_color_lod0_img") + .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_lod1_img") + .image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_lod2_img") + .image(3, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_lod3_img") + .image(4, GPU_R16F, Qualifier::READ, ImageType::FLOAT_2D, "in_coc_lod0_img") + .image(5, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_coc_lod1_img") + .image(6, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_coc_lod2_img") + .image(7, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_coc_lod3_img") + .compute_source("eevee_depth_of_field_reduce_comp.glsl"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle-Of-Confusion Tiles + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_tiles_flatten) + .do_static_compilation(true) + .local_group_size(DOF_TILES_FLATTEN_GROUP_SIZE, DOF_TILES_FLATTEN_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view") + .sampler(0, ImageType::FLOAT_2D, "coc_tx") + .image(2, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_fg_img") + .image(3, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_bg_img") + .compute_source("eevee_depth_of_field_tiles_flatten_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_tiles_dilate) + .additional_info("eevee_shared", "draw_view", "eevee_depth_of_field_tiles_common") + .local_group_size(DOF_TILES_DILATE_GROUP_SIZE, DOF_TILES_DILATE_GROUP_SIZE) + .image(2, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_fg_img") + .image(3, GPU_R11F_G11F_B10F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_bg_img") + .push_constant(Type::INT, "ring_count") + .push_constant(Type::INT, "ring_width_multiplier") + .compute_source("eevee_depth_of_field_tiles_dilate_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_tiles_dilate_minabs) + .do_static_compilation(true) + .define("DILATE_MODE_MIN_MAX", "false") + .additional_info("eevee_depth_of_field_tiles_dilate"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_tiles_dilate_minmax) + .do_static_compilation(true) + .define("DILATE_MODE_MIN_MAX", "true") + .additional_info("eevee_depth_of_field_tiles_dilate"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_tiles_common) + .image(0, GPU_R11F_G11F_B10F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_fg_img") + .image(1, GPU_R11F_G11F_B10F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_bg_img"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Variations + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_no_lut) + .define("DOF_BOKEH_TEXTURE", "false") + /** + * WORKAROUND(@fclem): This is to keep the code as is for now. The bokeh_lut_tx is referenced + * even if not used after optimization. But we don't want to include it in the create infos. + */ + .define("bokeh_lut_tx", "color_tx"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_lut) + .define("DOF_BOKEH_TEXTURE", "true") + .sampler(5, ImageType::FLOAT_2D, "bokeh_lut_tx"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_background).define("DOF_FOREGROUND_PASS", "false"); +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_foreground).define("DOF_FOREGROUND_PASS", "true"); + +#define EEVEE_DOF_FINAL_VARIATION(name, ...) \ + GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true); + +#define EEVEE_DOF_LUT_VARIATIONS(prefix, ...) \ + EEVEE_DOF_FINAL_VARIATION(prefix##_lut, "eevee_depth_of_field_lut", __VA_ARGS__) \ + EEVEE_DOF_FINAL_VARIATION(prefix##_no_lut, "eevee_depth_of_field_no_lut", __VA_ARGS__) + +#define EEVEE_DOF_GROUND_VARIATIONS(name, ...) \ + EEVEE_DOF_LUT_VARIATIONS(name##_background, "eevee_depth_of_field_background", __VA_ARGS__) \ + EEVEE_DOF_LUT_VARIATIONS(name##_foreground, "eevee_depth_of_field_foreground", __VA_ARGS__) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Gather + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_gather_common) + .additional_info("eevee_shared", + "draw_view", + "eevee_depth_of_field_tiles_common", + "eevee_sampling_data") + .uniform_buf(2, "DepthOfFieldData", "dof_buf") + .local_group_size(DOF_GATHER_GROUP_SIZE, DOF_GATHER_GROUP_SIZE) + .sampler(0, ImageType::FLOAT_2D, "color_tx") + .sampler(1, ImageType::FLOAT_2D, "color_bilinear_tx") + .sampler(2, ImageType::FLOAT_2D, "coc_tx") + .image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .image(3, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_weight_img"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_gather) + .image(4, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_occlusion_img") + .compute_source("eevee_depth_of_field_gather_comp.glsl") + .additional_info("eevee_depth_of_field_gather_common"); + +EEVEE_DOF_GROUND_VARIATIONS(eevee_depth_of_field_gather, "eevee_depth_of_field_gather") + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_hole_fill) + .do_static_compilation(true) + .compute_source("eevee_depth_of_field_hole_fill_comp.glsl") + .additional_info("eevee_depth_of_field_gather_common", "eevee_depth_of_field_no_lut"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_filter) + .do_static_compilation(true) + .local_group_size(DOF_FILTER_GROUP_SIZE, DOF_FILTER_GROUP_SIZE) + .additional_info("eevee_shared") + .sampler(0, ImageType::FLOAT_2D, "color_tx") + .sampler(1, ImageType::FLOAT_2D, "weight_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_weight_img") + .compute_source("eevee_depth_of_field_filter_comp.glsl"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Scatter + * \{ */ + +GPU_SHADER_INTERFACE_INFO(eevee_depth_of_field_scatter_iface, "interp") + /** Colors, weights, and Circle of confusion radii for the 4 pixels to scatter. */ + .flat(Type::VEC4, "color_and_coc1") + .flat(Type::VEC4, "color_and_coc2") + .flat(Type::VEC4, "color_and_coc3") + .flat(Type::VEC4, "color_and_coc4") + /** Sprite pixel position with origin at sprite center. In pixels. */ + .no_perspective(Type::VEC2, "rect_uv1") + .no_perspective(Type::VEC2, "rect_uv2") + .no_perspective(Type::VEC2, "rect_uv3") + .no_perspective(Type::VEC2, "rect_uv4") + /** Scaling factor for the bokeh distance. */ + .flat(Type::FLOAT, "distance_scale"); + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_scatter) + .do_static_compilation(true) + .additional_info("eevee_shared", "draw_view") + .sampler(0, ImageType::FLOAT_2D, "occlusion_tx") + .sampler(1, ImageType::FLOAT_2D, "bokeh_lut_tx") + .storage_buf(0, Qualifier::READ, "ScatterRect", "scatter_list_buf[]") + .fragment_out(0, Type::VEC4, "out_color") + .push_constant(Type::BOOL, "use_bokeh_lut") + .vertex_out(eevee_depth_of_field_scatter_iface) + .vertex_source("eevee_depth_of_field_scatter_vert.glsl") + .fragment_source("eevee_depth_of_field_scatter_frag.glsl"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Resolve + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_depth_of_field_resolve) + .define("DOF_RESOLVE_PASS", "true") + .local_group_size(DOF_RESOLVE_GROUP_SIZE, DOF_RESOLVE_GROUP_SIZE) + .additional_info("eevee_shared", + "draw_view", + "eevee_depth_of_field_tiles_common", + "eevee_sampling_data") + .uniform_buf(2, "DepthOfFieldData", "dof_buf") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .sampler(1, ImageType::FLOAT_2D, "color_tx") + .sampler(2, ImageType::FLOAT_2D, "color_bg_tx") + .sampler(3, ImageType::FLOAT_2D, "color_fg_tx") + .sampler(4, ImageType::FLOAT_2D, "color_hole_fill_tx") + .sampler(7, ImageType::FLOAT_2D, "weight_bg_tx") + .sampler(8, ImageType::FLOAT_2D, "weight_fg_tx") + .sampler(9, ImageType::FLOAT_2D, "weight_hole_fill_tx") + .sampler(10, ImageType::FLOAT_2D, "stable_color_tx") + .image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .compute_source("eevee_depth_of_field_resolve_comp.glsl"); + +EEVEE_DOF_LUT_VARIATIONS(eevee_depth_of_field_resolve, "eevee_depth_of_field_resolve") + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 2368061402c..db3cfc4a7a2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -12,8 +12,9 @@ GPU_SHADER_CREATE_INFO(eevee_shared) .typedef_source("eevee_shader_shared.hh"); GPU_SHADER_CREATE_INFO(eevee_sampling_data) + .define("EEVEE_SAMPLING_DATA") .additional_info("eevee_shared") - .uniform_buf(14, "SamplingData", "sampling_buf"); + .storage_buf(14, Qualifier::READ, "SamplingData", "sampling_buf"); /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh new file mode 100644 index 00000000000..d6ff34b0ed2 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view", "eevee_velocity_camera") + .uniform_buf(4, "MotionBlurData", "motion_blur_buf") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_img") + .compute_source("eevee_motion_blur_flatten_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_viewport) + .do_static_compilation(true) + .define("FLATTEN_VIEWPORT") + .image(0, GPU_RG16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img") + .additional_info("eevee_motion_blur_tiles_flatten"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_render) + .do_static_compilation(true) + .image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img") + .additional_info("eevee_motion_blur_tiles_flatten"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_dilate) + .do_static_compilation(true) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared") + /* NOTE: See MotionBlurTileIndirection. */ + .storage_buf(0, Qualifier::READ_WRITE, "uint", "tile_indirection_buf[]") + .image(1, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img") + .compute_source("eevee_motion_blur_dilate_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_gather) + .do_static_compilation(true) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view", "eevee_sampling_data") + .uniform_buf(4, "MotionBlurData", "motion_blur_buf") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .sampler(1, ImageType::FLOAT_2D, "velocity_tx") + .sampler(2, ImageType::FLOAT_2D, "in_color_tx") + /* NOTE: See MotionBlurTileIndirection. */ + .storage_buf(0, Qualifier::READ, "uint", "tile_indirection_buf[]") + .image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img") + .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .compute_source("eevee_motion_blur_gather_comp.glsl"); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl index f28a809fdab..606292bbe83 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl @@ -96,7 +96,7 @@ void main() float dist_raw = texelFetch(lineTex, center_texel, 0).b; float dist = decode_line_dist(dist_raw); - /* TODO: Opti: use textureGather. */ + /* TODO: Optimization: use textureGather. */ vec4 neightbor_col0 = texelFetchOffset(colorTex, center_texel, 0, ivec2(1, 0)); vec4 neightbor_col1 = texelFetchOffset(colorTex, center_texel, 0, ivec2(-1, 0)); vec4 neightbor_col2 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, 1)); diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 88ae5ac707e..026a1f52ac1 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -201,7 +201,7 @@ static void select_cache_populate(void *vedata, Object *ob) if (!e_data.context.is_dirty && sel_data && sel_data->is_drawn) { /* The object indices have already been drawn. Fill depth pass. - * Opti: Most of the time this depth pass is not used. */ + * Optimization: Most of the time this depth pass is not used. */ struct Mesh *me = ob->data; if (e_data.context.select_mode & SCE_SELECT_FACE) { struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 8e61c25be71..5405afd2a90 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -57,6 +57,7 @@ #include "MEM_guardedalloc.h" +#include "draw_manager.h" #include "draw_texture_pool.h" #include "BLI_math_vec_types.hh" @@ -182,7 +183,7 @@ class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable GPU_uniformbuf_free(ubo_); } - void push_update(void) + void push_update() { GPU_uniformbuf_update(ubo_, this->data_); } @@ -227,12 +228,17 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable GPU_storagebuf_free(ssbo_); } - void push_update(void) + void push_update() { BLI_assert(device_only == false); GPU_storagebuf_update(ssbo_, this->data_); } + void clear_to_zero() + { + GPU_storagebuf_clear_to_zero(ssbo_); + } + operator GPUStorageBuf *() const { return ssbo_; @@ -319,6 +325,7 @@ class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> { MEM_freeN(this->data_); } + /* Resize to \a new_size elements. */ void resize(int64_t new_size) { BLI_assert(new_size > 0); @@ -595,42 +602,47 @@ class Texture : NonCopyable { /** * Returns true if the texture has been allocated or acquired from the pool. */ - bool is_valid(void) const + bool is_valid() const { return tx_ != nullptr; } - int width(void) const + int width() const { return GPU_texture_width(tx_); } - int height(void) const + int height() const { return GPU_texture_height(tx_); } - bool depth(void) const + int pixel_count() const + { + return GPU_texture_width(tx_) * GPU_texture_height(tx_); + } + + bool depth() const { return GPU_texture_depth(tx_); } - bool is_stencil(void) const + bool is_stencil() const { return GPU_texture_stencil(tx_); } - bool is_integer(void) const + bool is_integer() const { return GPU_texture_integer(tx_); } - bool is_cube(void) const + bool is_cube() const { return GPU_texture_cube(tx_); } - bool is_array(void) const + bool is_array() const { return GPU_texture_array(tx_); } @@ -722,7 +734,7 @@ class Texture : NonCopyable { int3 size = this->size(); if (size != int3(w, h, d) || GPU_texture_format(tx_) != format || GPU_texture_cube(tx_) != cubemap || GPU_texture_array(tx_) != layered) { - GPU_TEXTURE_FREE_SAFE(tx_); + free(); } } if (tx_ == nullptr) { @@ -772,50 +784,45 @@ class Texture : NonCopyable { }; class TextureFromPool : public Texture, NonMovable { - private: - GPUTexture *tx_tmp_saved_ = nullptr; - public: TextureFromPool(const char *name = "gpu::Texture") : Texture(name){}; - /* Always use `release()` after rendering and `sync()` in sync phase. */ - void acquire(int2 extent, eGPUTextureFormat format, void *owner_) + /* Always use `release()` after rendering. */ + void acquire(int2 extent, eGPUTextureFormat format) { BLI_assert(this->tx_ == nullptr); - if (this->tx_ != nullptr) { - return; - } - if (tx_tmp_saved_ != nullptr) { - if (GPU_texture_width(tx_tmp_saved_) != extent.x || - GPU_texture_height(tx_tmp_saved_) != extent.y || - GPU_texture_format(tx_tmp_saved_) != format) { - this->tx_tmp_saved_ = nullptr; - } - else { - this->tx_ = tx_tmp_saved_; - return; - } - } - DrawEngineType *owner = (DrawEngineType *)owner_; - this->tx_ = DRW_texture_pool_query_2d(UNPACK2(extent), format, owner); + + this->tx_ = DRW_texture_pool_texture_acquire( + DST.vmempool->texture_pool, UNPACK2(extent), format); } - void release(void) + void release() { /* Allows multiple release. */ - if (this->tx_ != nullptr) { - tx_tmp_saved_ = this->tx_; - this->tx_ = nullptr; + if (this->tx_ == nullptr) { + return; } + DRW_texture_pool_texture_release(DST.vmempool->texture_pool, this->tx_); + this->tx_ = nullptr; } /** - * Clears any reference. Workaround for pool texture not being able to release on demand. - * Needs to be called at during the sync phase. + * Swap the content of the two textures. + * Also change ownership accordingly if needed. */ - void sync(void) + static void swap(TextureFromPool &a, Texture &b) { - tx_tmp_saved_ = nullptr; + Texture::swap(a, b); + DRW_texture_pool_give_texture_ownership(DST.vmempool->texture_pool, a); + DRW_texture_pool_take_texture_ownership(DST.vmempool->texture_pool, b); + } + static void swap(Texture &a, TextureFromPool &b) + { + swap(b, a); + } + static void swap(TextureFromPool &a, TextureFromPool &b) + { + Texture::swap(a, b); } /** Remove methods that are forbidden with this type of textures. */ @@ -902,45 +909,47 @@ class Framebuffer : NonCopyable { template<typename T, int64_t len> class SwapChain { private: + BLI_STATIC_ASSERT(len > 1, "A swap-chain needs more than 1 unit in length."); std::array<T, len> chain_; - int64_t index_ = 0; public: void swap() { - index_ = (index_ + 1) % len; + for (auto i : IndexRange(len - 1)) { + T::swap(chain_[i], chain_[(i + 1) % len]); + } } T ¤t() { - return chain_[index_]; + return chain_[0]; } T &previous() { /* Avoid modulo operation with negative numbers. */ - return chain_[(index_ + len - 1) % len]; + return chain_[(0 + len - 1) % len]; } T &next() { - return chain_[(index_ + 1) % len]; + return chain_[(0 + 1) % len]; } const T ¤t() const { - return chain_[index_]; + return chain_[0]; } const T &previous() const { /* Avoid modulo operation with negative numbers. */ - return chain_[(index_ + len - 1) % len]; + return chain_[(0 + len - 1) % len]; } const T &next() const { - return chain_[(index_ + 1) % len]; + return chain_[(0 + 1) % len]; } }; diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index c2d26badc4c..a3097251d35 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -454,6 +454,10 @@ void DRW_shgroup_call_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf * void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count); void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count); void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count); +void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, + GPUPrimType primitive_type, + Object *ob, + GPUStorageBuf *indirect_buf); /** * \warning Only use with Shaders that have `IN_PLACE_INSTANCES` defined. * TODO: Should be removed. @@ -791,7 +795,7 @@ bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox); bool DRW_culling_plane_test(const DRWView *view, const float plane[4]); /** * Return True if the given box intersect the current view frustum. - * This function will have to be replaced when world space bb per objects is implemented. + * This function will have to be replaced when world space bounding-box per objects is implemented. */ bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3]); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index f846251c66b..4c0f025e934 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -90,6 +90,7 @@ static struct DRWShapeCache { GPUBatch *drw_procedural_verts; GPUBatch *drw_procedural_lines; GPUBatch *drw_procedural_tris; + GPUBatch *drw_procedural_tri_strips; GPUBatch *drw_cursor; GPUBatch *drw_cursor_only_circle; GPUBatch *drw_fullscreen_quad; @@ -208,6 +209,21 @@ GPUBatch *drw_cache_procedural_triangles_get(void) return SHC.drw_procedural_tris; } +GPUBatch *drw_cache_procedural_triangle_strips_get() +{ + if (!SHC.drw_procedural_tri_strips) { + /* TODO(fclem): get rid of this dummy VBO. */ + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, 1); + + SHC.drw_procedural_tri_strips = GPU_batch_create_ex( + GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); + } + return SHC.drw_procedural_tri_strips; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index d1eb937d711..5de9f1b44c8 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -293,26 +293,28 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, for (int i = 0; i < gpumat_array_len; i++) { GPUMaterial *gpumat = gpumat_array[i]; - if (gpumat) { - ListBase gpu_attrs = GPU_material_attributes(gpumat); - LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { - const char *name = gpu_attr->name; - eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type); - int layer = -1; - std::optional<eAttrDomain> domain; - - if (gpu_attr->is_default_color) { - name = default_color_name.c_str(); - } + if (gpumat == nullptr) { + continue; + } + ListBase gpu_attrs = GPU_material_attributes(gpumat); + LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { + const char *name = gpu_attr->name; + eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type); + int layer = -1; + std::optional<eAttrDomain> domain; + + if (gpu_attr->is_default_color) { + name = default_color_name.c_str(); + } - if (type == CD_AUTO_FROM_NAME) { - /* We need to deduce what exact layer is used. - * - * We do it based on the specified name. - */ - if (name[0] != '\0') { - layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name); - type = CD_MTFACE; + if (type == CD_AUTO_FROM_NAME) { + /* We need to deduce what exact layer is used. + * + * We do it based on the specified name. + */ + if (name[0] != '\0') { + layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name); + type = CD_MTFACE; #if 0 /* Tangents are always from UV's - this will never happen. */ if (layer == -1) { @@ -320,88 +322,87 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, type = CD_TANGENT; } #endif - if (layer == -1) { - /* Try to match a generic attribute, we use the first attribute domain with a - * matching name. */ - if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) { - domain = ATTR_DOMAIN_POINT; - } - else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) { - domain = ATTR_DOMAIN_CORNER; - } - else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) { - domain = ATTR_DOMAIN_FACE; - } - else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) { - domain = ATTR_DOMAIN_EDGE; - } - else { - layer = -1; - } + if (layer == -1) { + /* Try to match a generic attribute, we use the first attribute domain with a + * matching name. */ + if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) { + domain = ATTR_DOMAIN_POINT; } - - if (layer == -1) { - continue; + else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) { + domain = ATTR_DOMAIN_CORNER; + } + else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) { + domain = ATTR_DOMAIN_FACE; + } + else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) { + domain = ATTR_DOMAIN_EDGE; + } + else { + layer = -1; } } - else { - /* Fall back to the UV layer, which matches old behavior. */ - type = CD_MTFACE; + + if (layer == -1) { + continue; } } + else { + /* Fall back to the UV layer, which matches old behavior. */ + type = CD_MTFACE; + } + } - switch (type) { - case CD_MTFACE: { - if (layer == -1) { - layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - } - if (layer != -1) { - cd_used.uv |= (1 << layer); - } - break; + switch (type) { + case CD_MTFACE: { + if (layer == -1) { + layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); } - case CD_TANGENT: { - if (layer == -1) { - layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : - CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - - /* Only fallback to orco (below) when we have no UV layers, see: T56545 */ - if (layer == -1 && name[0] != '\0') { - layer = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); - } - } - if (layer != -1) { - cd_used.tan |= (1 << layer); - } - else { - /* no UV layers at all => requesting orco */ - cd_used.tan_orco = 1; - cd_used.orco = 1; + if (layer != -1) { + cd_used.uv |= (1 << layer); + } + break; + } + case CD_TANGENT: { + if (layer == -1) { + layer = (name[0] != '\0') ? CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) : + CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); + + /* Only fallback to orco (below) when we have no UV layers, see: T56545 */ + if (layer == -1 && name[0] != '\0') { + layer = CustomData_get_render_layer(cd_ldata, CD_MLOOPUV); } - break; } - - case CD_ORCO: { + if (layer != -1) { + cd_used.tan |= (1 << layer); + } + else { + /* no UV layers at all => requesting orco */ + cd_used.tan_orco = 1; cd_used.orco = 1; - break; } - case CD_PROP_BYTE_COLOR: - case CD_PROP_COLOR: - case CD_PROP_FLOAT3: - case CD_PROP_BOOL: - case CD_PROP_INT8: - case CD_PROP_INT32: - case CD_PROP_FLOAT: - case CD_PROP_FLOAT2: { - if (layer != -1 && domain.has_value()) { - drw_attributes_add_request(attributes, name, type, layer, *domain); - } - break; + break; + } + + case CD_ORCO: { + cd_used.orco = 1; + break; + } + case CD_PROP_BYTE_COLOR: + case CD_PROP_COLOR: + case CD_PROP_FLOAT3: + case CD_PROP_BOOL: + case CD_PROP_INT8: + case CD_PROP_INT32: + case CD_PROP_FLOAT: + case CD_PROP_FLOAT2: { + if (layer != -1 && domain.has_value()) { + drw_attributes_add_request(attributes, name, type, layer, *domain); } - default: - break; + break; } + default: + break; } } } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 419b13edf1f..411123f00bf 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -188,6 +188,7 @@ typedef enum { DRW_CMD_DRAW_INSTANCE = 2, DRW_CMD_DRAW_INSTANCE_RANGE = 3, DRW_CMD_DRAW_PROCEDURAL = 4, + DRW_CMD_DRAW_INDIRECT = 5, /* Compute Commands. */ DRW_CMD_COMPUTE = 8, @@ -203,7 +204,7 @@ typedef enum { /* Needs to fit in 4bits */ } eDRWCommandType; -#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL +#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_INDIRECT typedef struct DRWCommandDraw { GPUBatch *batch; @@ -232,6 +233,12 @@ typedef struct DRWCommandDrawInstanceRange { uint inst_count; } DRWCommandDrawInstanceRange; +typedef struct DRWCommandDrawIndirect { + GPUBatch *batch; + DRWResourceHandle handle; + GPUStorageBuf *indirect_buf; +} DRWCommandDrawIndirect; + typedef struct DRWCommandCompute { int groups_x_len; int groups_y_len; @@ -286,6 +293,7 @@ typedef union DRWCommand { DRWCommandDrawInstance instance; DRWCommandDrawInstanceRange instance_range; DRWCommandDrawProcedural procedural; + DRWCommandDrawIndirect draw_indirect; DRWCommandCompute compute; DRWCommandComputeRef compute_ref; DRWCommandComputeIndirect compute_indirect; @@ -685,6 +693,7 @@ void drw_resource_buffer_finish(DRWData *vmempool); GPUBatch *drw_cache_procedural_points_get(void); GPUBatch *drw_cache_procedural_lines_get(void); GPUBatch *drw_cache_procedural_triangles_get(void); +GPUBatch *drw_cache_procedural_triangle_strips_get(void); void drw_uniform_attrs_pool_update(struct GHash *table, struct GPUUniformAttrList *key, diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 188d9114cd7..9392efcf92b 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -878,6 +878,17 @@ static void drw_command_draw_procedural(DRWShadingGroup *shgroup, cmd->vert_count = vert_count; } +static void drw_command_draw_indirect(DRWShadingGroup *shgroup, + GPUBatch *batch, + DRWResourceHandle handle, + GPUStorageBuf *indirect_buf) +{ + DRWCommandDrawIndirect *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INDIRECT); + cmd->batch = batch; + cmd->handle = handle; + cmd->indirect_buf = indirect_buf; +} + static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id) { /* Only one can be valid. */ @@ -1005,6 +1016,7 @@ void DRW_shgroup_call_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf * drw_command_compute_indirect(shgroup, indirect_buf); } + void DRW_shgroup_barrier(DRWShadingGroup *shgroup, eGPUBarrier type) { BLI_assert(GPU_compute_shader_support()); @@ -1044,6 +1056,38 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob, drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tri_count * 3); } +void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, + GPUPrimType primitive_type, + Object *ob, + GPUStorageBuf *indirect_buf) +{ + struct GPUBatch *geom = NULL; + switch (primitive_type) { + case GPU_PRIM_POINTS: + geom = drw_cache_procedural_points_get(); + break; + case GPU_PRIM_LINES: + geom = drw_cache_procedural_lines_get(); + break; + case GPU_PRIM_TRIS: + geom = drw_cache_procedural_triangles_get(); + break; + case GPU_PRIM_TRI_STRIP: + geom = drw_cache_procedural_triangle_strips_get(); + break; + default: + BLI_assert_msg(0, + "Unsupported primitive type in DRW_shgroup_call_procedural_indirect. Add new " + "one as needed."); + break; + } + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + drw_command_draw_indirect(shgroup, geom, handle, indirect_buf); +} + void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index e7e0e0ce41f..4dda0ceb2ef 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -318,6 +318,7 @@ void DRW_state_reset(void) DRW_state_reset_ex(DRW_STATE_DEFAULT); GPU_texture_unbind_all(); + GPU_texture_image_unbind_all(); GPU_uniformbuf_unbind_all(); GPU_storagebuf_unbind_all(); @@ -874,6 +875,25 @@ static void draw_call_single_do(DRWShadingGroup *shgroup, state->baseinst_loc); } +/* Not to be mistaken with draw_indirect_call which does batch many drawcalls together. This one + * only execute an indirect drawcall with user indirect buffer. */ +static void draw_call_indirect(DRWShadingGroup *shgroup, + DRWCommandsState *state, + GPUBatch *batch, + DRWResourceHandle handle, + GPUStorageBuf *indirect_buf) +{ + draw_call_batching_flush(shgroup, state); + draw_call_resource_bind(state, &handle); + + if (G.f & G_FLAG_PICKSEL) { + GPU_select_load_id(state->select_id); + } + + GPU_batch_set_shader(batch, shgroup->shader); + GPU_batch_draw_indirect(batch, indirect_buf); +} + static void draw_call_batching_start(DRWCommandsState *state) { state->neg_scale = false; @@ -970,6 +990,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Unbinding can be costly. Skip in normal condition. */ if (G.debug & G_DEBUG_GPU) { GPU_texture_unbind_all(); + GPU_texture_image_unbind_all(); GPU_uniformbuf_unbind_all(); GPU_storagebuf_unbind_all(); } @@ -996,12 +1017,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) while ((cmd = draw_command_iter_step(&iter, &cmd_type))) { switch (cmd_type) { + case DRW_CMD_DRAW_PROCEDURAL: case DRW_CMD_DRWSTATE: case DRW_CMD_STENCIL: draw_call_batching_flush(shgroup, &state); break; case DRW_CMD_DRAW: - case DRW_CMD_DRAW_PROCEDURAL: + case DRW_CMD_DRAW_INDIRECT: case DRW_CMD_DRAW_INSTANCE: if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) { continue; @@ -1055,6 +1077,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) 1, true); break; + case DRW_CMD_DRAW_INDIRECT: + draw_call_indirect(shgroup, + &state, + cmd->draw_indirect.batch, + cmd->draw_indirect.handle, + cmd->draw_indirect.indirect_buf); + break; case DRW_CMD_DRAW_INSTANCE: draw_call_single_do(shgroup, &state, diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index e8944442607..fbcc78e52f9 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef GPU_SHADER +# pragma once + # include "GPU_shader.h" # include "GPU_shader_shared_utils.h" @@ -9,6 +11,9 @@ typedef struct ObjectMatrices ObjectMatrices; typedef struct ObjectInfos ObjectInfos; typedef struct VolumeInfos VolumeInfos; typedef struct CurvesInfos CurvesInfos; +typedef struct DrawCommand DrawCommand; +typedef struct DrawCommandIndexed DrawCommandIndexed; +typedef struct DispatchCommand DispatchCommand; #endif #define DRW_SHADER_SHARED_H @@ -96,3 +101,33 @@ BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 16) #define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) #define ObjectInfo (drw_infos[resource_id].drw_Infos) #define ObjectColor (drw_infos[resource_id].drw_ObjectColor) + +/* Indirect commands structures. */ + +struct DrawCommand { + uint v_count; + uint i_count; + uint v_first; + uint i_first; +}; +BLI_STATIC_ASSERT_ALIGN(DrawCommand, 16) + +struct DrawCommandIndexed { + uint v_count; + uint i_count; + uint v_first; + uint base_index; + uint i_first; + uint _pad0; + uint _pad1; + uint _pad2; +}; +BLI_STATIC_ASSERT_ALIGN(DrawCommandIndexed, 16) + +struct DispatchCommand { + uint num_groups_x; + uint num_groups_y; + uint num_groups_z; + uint _pad0; +}; +BLI_STATIC_ASSERT_ALIGN(DispatchCommand, 16) diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc index b36cb5c809e..017ecec7be2 100644 --- a/source/blender/draw/intern/draw_texture_pool.cc +++ b/source/blender/draw/intern/draw_texture_pool.cc @@ -160,6 +160,19 @@ void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex) pool->tmp_tex_released.append(tmp_tex); } +void DRW_texture_pool_take_texture_ownership(DRWTexturePool *pool, GPUTexture *tex) +{ + pool->tmp_tex_acquired.remove_first_occurrence_and_reorder(tex); +} + +void DRW_texture_pool_give_texture_ownership(DRWTexturePool *pool, GPUTexture *tex) +{ + BLI_assert(pool->tmp_tex_acquired.first_index_of_try(tex) == -1 && + pool->tmp_tex_released.first_index_of_try(tex) == -1 && + pool->tmp_tex_pruned.first_index_of_try(tex) == -1); + pool->tmp_tex_acquired.append(tex); +} + void DRW_texture_pool_reset(DRWTexturePool *pool) { pool->last_user_id = -1; diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h index 1c30ea88552..9fbbf630833 100644 --- a/source/blender/draw/intern/draw_texture_pool.h +++ b/source/blender/draw/intern/draw_texture_pool.h @@ -26,6 +26,7 @@ void DRW_texture_pool_free(DRWTexturePool *pool); /** * Try to find a texture corresponding to params into the texture pool. * If no texture was found, create one and add it to the pool. + * DEPRECATED: Use DRW_texture_pool_texture_acquire instead and do it just before rendering. */ GPUTexture *DRW_texture_pool_query( DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user); @@ -40,6 +41,22 @@ GPUTexture *DRW_texture_pool_texture_acquire(DRWTexturePool *pool, * Releases a previously acquired texture. */ void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex); + +/** + * This effectively remove a texture from the texture pool, giving full ownership to the caller. + * The given texture needs to be been acquired through DRW_texture_pool_texture_acquire(). + * IMPORTANT: This removes the need for a DRW_texture_pool_texture_release() call on this texture. + */ +void DRW_texture_pool_take_texture_ownership(DRWTexturePool *pool, GPUTexture *tex); +/** + * This Inserts a texture into the texture pool, giving full ownership to the texture pool. + * The texture needs not to be in the pool already. + * The texture may be reused in a latter call to DRW_texture_pool_texture_acquire(); + * IMPORTANT: DRW_texture_pool_texture_release() still needs to be called on this texture + * after usage. + */ +void DRW_texture_pool_give_texture_ownership(DRWTexturePool *pool, GPUTexture *tex); + /** * Resets the user bits for each texture in the pool and delete unused ones. */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 7f16837022c..64ade020418 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -58,7 +58,6 @@ template<typename AttributeType, typename VBOType> struct AttributeTypeConverter } }; -/* Similar to the one in #extract_mesh_vcol_vbo.cc */ struct gpuMeshCol { ushort r, g, b, a; }; diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl index ae82277d9a6..cb2da9d35bf 100644 --- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -10,6 +10,11 @@ float point_plane_projection_dist(vec3 line_origin, vec3 plane_origin, vec3 plan return dot(plane_normal, plane_origin - line_origin); } +float point_line_projection_dist(vec2 point, vec2 line_origin, vec2 line_normal) +{ + return dot(line_normal, line_origin - point); +} + float line_plane_intersect_dist(vec3 line_origin, vec3 line_direction, vec3 plane_origin, @@ -104,6 +109,25 @@ float line_unit_box_intersect_dist_safe(vec3 line_origin, vec3 line_direction) } /** + * Same as line_unit_box_intersect_dist but for 2D case. + */ +float line_unit_square_intersect_dist(vec2 line_origin, vec2 line_direction) +{ + vec2 first_plane = (vec2(1.0) - line_origin) / line_direction; + vec2 second_plane = (vec2(-1.0) - line_origin) / line_direction; + vec2 farthest_plane = max(first_plane, second_plane); + + return min_v2(farthest_plane); +} + +float line_unit_square_intersect_dist_safe(vec2 line_origin, vec2 line_direction) +{ + vec2 safe_line_direction = max(vec2(1e-8), abs(line_direction)) * + select(vec2(1.0), -vec2(1.0), lessThan(line_direction, vec2(0.0))); + return line_unit_square_intersect_dist(line_origin, safe_line_direction); +} + +/** * Returns clipping distance (intersection with the nearest plane) with the given axis-aligned * bound box along \a line_direction. * Safe even if \a line_direction is degenerate. diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 51f3c890df8..e081a0243ca 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -116,8 +116,8 @@ bool flag_test(int flag, int val) { return (flag & val) != 0; } void set_flag_from_test(inout uint value, bool test, uint flag) { if (test) { value |= flag; } else { value &= ~flag; } } void set_flag_from_test(inout int value, bool test, int flag) { if (test) { value |= flag; } else { value &= ~flag; } } -#define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights))); -#define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights))); +#define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights))) +#define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights))) /* clang-format on */ diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 3608140a29d..e7c7f679b16 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -402,6 +402,7 @@ static void draw_marker_name(const uchar *text_color, const uiFontStyle *fstyle, TimeMarker *marker, float marker_x, + float xmax, float text_y) { const char *name = marker->name; @@ -419,8 +420,16 @@ static void draw_marker_name(const uchar *text_color, } #endif - int name_x = marker_x + UI_DPI_ICON_SIZE * 0.6; - UI_fontstyle_draw_simple(fstyle, name_x, text_y, name, final_text_color); + const int icon_half_width = UI_DPI_ICON_SIZE * 0.6; + const struct uiFontStyleDraw_Params fs_params = {.align = UI_STYLE_TEXT_LEFT, .word_wrap = 0}; + const struct rcti rect = { + .xmin = marker_x + icon_half_width, + .xmax = xmax - icon_half_width, + .ymin = text_y, + .ymax = text_y, + }; + + UI_fontstyle_draw(fstyle, &rect, name, strlen(name), final_text_color, &fs_params); } static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax) @@ -462,8 +471,13 @@ static int marker_get_icon_id(TimeMarker *marker, int flag) return (marker->flag & SELECT) ? ICON_MARKER_HLT : ICON_MARKER; } -static void draw_marker( - const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int xpos, int flag, int region_height) +static void draw_marker(const uiFontStyle *fstyle, + TimeMarker *marker, + int xpos, + int xmax, + int flag, + int region_height, + bool is_elevated) { uchar line_color[4], text_color[4]; @@ -479,12 +493,11 @@ static void draw_marker( GPU_blend(GPU_BLEND_NONE); float name_y = UI_DPI_FAC * 18; - /* Give an offset to the marker name when selected, - * or when near the current frame (5 frames range, starting from the current one). */ - if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) { + /* Give an offset to the marker that is elevated. */ + if (is_elevated) { name_y += UI_DPI_FAC * 10; } - draw_marker_name(text_color, fstyle, marker, xpos, name_y); + draw_marker_name(text_color, fstyle, marker, xpos, xmax, name_y); } static void draw_markers_background(rctf *rect) @@ -532,6 +545,14 @@ static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2 r_range[1] = v2d->cur.xmax + font_width_max; } +static int markers_frame_sort(const void *a, const void *b) +{ + const TimeMarker *marker_a = a; + const TimeMarker *marker_b = b; + + return marker_a->frame > marker_b->frame; +} + void ED_markers_draw(const bContext *C, int flag) { ListBase *markers = ED_context_get_markers(C); @@ -561,22 +582,69 @@ void ED_markers_draw(const bContext *C, int flag) const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - /* Separate loops in order to draw selected markers on top */ - LISTBASE_FOREACH (TimeMarker *, marker, markers) { - if ((marker->flag & SELECT) == 0) { - if (marker_is_in_frame_range(marker, clip_frame_range)) { - draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy); - } + /* Markers are not stored by frame order, so we need to sort it here. */ + ListBase sorted_markers; + + BLI_duplicatelist(&sorted_markers, markers); + BLI_listbase_sort(&sorted_markers, markers_frame_sort); + + /** + * Set a temporary bit in the marker's flag to indicate that it should be elevated. + * This bit will be flipped back at the end of this function. + */ + const int ELEVATED = 0x10; + LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) { + const bool is_elevated = (marker->flag & SELECT) || + (cfra >= marker->frame && + (marker->next == NULL || cfra < marker->next->frame)); + SET_FLAG_FROM_TEST(marker->flag, is_elevated, ELEVATED); + } + + /* Separate loops in order to draw selected markers on top. */ + + /** + * Draw non-elevated markers first. + * Note that unlike the elevated markers, these marker names will always be clipped by the + * proceeding marker. This is done because otherwise, the text overlaps with the icon of the + * marker itself. + */ + LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) { + if ((marker->flag & ELEVATED) == 0 && marker_is_in_frame_range(marker, clip_frame_range)) { + const int xmax = marker->next ? marker->next->frame : clip_frame_range[1] + 1; + draw_marker( + fstyle, marker, marker->frame * xscale, xmax * xscale, flag, region->winy, false); } } - LISTBASE_FOREACH (TimeMarker *, marker, markers) { - if (marker->flag & SELECT) { - if (marker_is_in_frame_range(marker, clip_frame_range)) { - draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy); - } + + /* Now draw the elevated markers */ + for (TimeMarker *marker = sorted_markers.first; marker != NULL;) { + + /* Skip this marker if it is elevated or out of the frame range. */ + if ((marker->flag & ELEVATED) == 0 || !marker_is_in_frame_range(marker, clip_frame_range)) { + marker = marker->next; + continue; } + + /* Find the next elevated marker. */ + /* We use the next marker to determine how wide our text should be */ + TimeMarker *next_marker = marker->next; + while (next_marker != NULL && (next_marker->flag & ELEVATED) == 0) { + next_marker = next_marker->next; + } + + const int xmax = next_marker ? next_marker->frame : clip_frame_range[1] + 1; + draw_marker(fstyle, marker, marker->frame * xscale, xmax * xscale, flag, region->winy, true); + + marker = next_marker; } + /* Reset the elevated flag. */ + LISTBASE_FOREACH (TimeMarker *, marker, &sorted_markers) { + marker->flag &= ~ELEVATED; + } + + BLI_freelistN(&sorted_markers); + GPU_matrix_pop(); } diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h index 2dc67fc4d37..b54f81004f2 100644 --- a/source/blender/editors/asset/ED_asset_list.h +++ b/source/blender/editors/asset/ED_asset_list.h @@ -24,7 +24,7 @@ struct wmNotifier; void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, const struct bContext *C); void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, - struct bContext *C); + const struct bContext *C); void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference); /** 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 67e253a4fcd..773838a54cd 100644 --- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -97,10 +97,8 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf( RNA_enum_item_add_separator(&item, &totitem); } - int i = 0; - for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first; - user_library; - user_library = user_library->next, i++) { + int i; + LISTBASE_FOREACH_INDEX (bUserAssetLibrary *, user_library, &U.asset_libraries, i) { /* Note that the path itself isn't checked for validity here. If an invalid library path is * used, the Asset Browser can give a nice hint on what's wrong. */ const bool is_valid = (user_library->name[0] && user_library->path[0]); diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 55167c1ed2d..b0ff5c86520 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -110,7 +110,7 @@ class AssetList : NonCopyable { void setup(); void fetch(const bContext &C); - void ensurePreviewsJob(bContext *C); + void ensurePreviewsJob(const bContext *C); void clear(bContext *C); bool needsRefetch() const; @@ -212,7 +212,7 @@ void AssetList::iterate(AssetListIterFn fn) const } } -void AssetList::ensurePreviewsJob(bContext *C) +void AssetList::ensurePreviewsJob(const bContext *C) { FileList *files = filelist_; int numfiles = filelist_files_ensure(files); @@ -422,7 +422,8 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, AssetListStorage::fetch_library(*library_reference, *C); } -void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C) +void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, + const bContext *C) { AssetList *list = AssetListStorage::lookup_list(*library_reference); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 24302aca59b..852bfb00ea6 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1541,67 +1541,6 @@ void CURVE_OT_split(wmOperatorType *ot) /** \name Flag Utility Functions * \{ */ -static bool isNurbselUV(const Nurb *nu, uint8_t flag, int *r_u, int *r_v) -{ - /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv - * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu - */ - BPoint *bp; - int a, b, sel; - - *r_u = *r_v = -1; - - bp = nu->bp; - for (b = 0; b < nu->pntsv; b++) { - sel = 0; - for (a = 0; a < nu->pntsu; a++, bp++) { - if (bp->f1 & flag) { - sel++; - } - } - if (sel == nu->pntsu) { - if (*r_u == -1) { - *r_u = b; - } - else { - return 0; - } - } - else if (sel > 1) { - return 0; /* because sel == 1 is still ok */ - } - } - - for (a = 0; a < nu->pntsu; a++) { - sel = 0; - bp = &nu->bp[a]; - for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) { - if (bp->f1 & flag) { - sel++; - } - } - if (sel == nu->pntsv) { - if (*r_v == -1) { - *r_v = a; - } - else { - return 0; - } - } - else if (sel > 1) { - return 0; - } - } - - if (*r_u == -1 && *r_v > -1) { - return 1; - } - if (*r_v == -1 && *r_u > -1) { - return 1; - } - return 0; -} - /* return true if U direction is selected and number of selected columns v */ static bool isNurbselU(Nurb *nu, int *v, int flag) { @@ -1976,119 +1915,201 @@ static void ed_curve_delete_selected(Object *obedit, View3D *v3d) } } -bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag) +static void select_bpoints(BPoint *bp, + const int stride, + const int count, + const bool selstatus, + const uint8_t flag, + const bool hidden) { - BPoint *bp, *bpn, *newbp; - int a, u, v, len; - bool ok = false; + for (int i = 0; i < count; i++) { + select_bpoint(bp, selstatus, flag, hidden); + bp += stride; + } +} - LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) { - if (nu->pntsv == 1) { - bp = nu->bp; - a = nu->pntsu; - while (a) { - if (bp->f1 & flag) { - /* pass */ - } - else { - break; - } - bp++; - a--; - } - if (a == 0) { - ok = true; - newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1"); - ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu); - bp = newbp + nu->pntsu; - ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu); - MEM_freeN(nu->bp); - nu->bp = newbp; - a = nu->pntsu; - while (a--) { - select_bpoint(bp, SELECT, flag, HIDDEN); - select_bpoint(newbp, DESELECT, flag, HIDDEN); - bp++; - newbp++; - } +/** + * Calculate and return fully selected legs along i dimension. + * Calculates intervals to create extrusion by duplicating existing points while copied to + * destination NURBS. For ex. for curve of 3 points indexed by 0..2 to extrude first and last + * point copy intervals would be [0, 0][0, 2][2, 2]. Representation in copy_intervals array would + * be [0, 0, 2, 2]. Returns -1 if selection is not valid. + */ +static int sel_to_copy_ints(const BPoint *bp, + const int next_j, + const int max_j, + const int next_i, + const int max_i, + const uint8_t flag, + int copy_intervals[], + int *interval_count, + bool *out_is_first_sel) +{ + const BPoint *bp_j = bp; - nu->pntsv = 2; - nu->orderv = 2; - BKE_nurb_knot_calc_v(nu); - } - } - else { - /* which row or column is selected */ + int selected_leg_count = 0; + int ins = 0; + int selected_in_prev_leg = -1; + int not_full = -1; - if (isNurbselUV(nu, flag, &u, &v)) { + bool is_first_sel = false; + bool is_last_sel = false; - /* deselect all */ - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - select_bpoint(bp, DESELECT, flag, HIDDEN); - bp++; - } + for (int j = 0; j < max_j; j++, bp_j += next_j) { + const BPoint *bp_j_i = bp_j; + int selected_in_curr_leg = 0; + for (int i = 0; i < max_i; i++, bp_j_i += next_i) { + if (bp_j_i->f1 & flag) { + selected_in_curr_leg++; + } + } + if (selected_in_curr_leg == max_i) { + selected_leg_count++; + if (j == 0) { + is_first_sel = true; + } + else if (j + 1 == max_j) { + is_last_sel = true; + } + } + else if (not_full == -1) { + not_full = selected_in_curr_leg; + } + /* We have partialy selected leg in opposite dimension if condition is met. */ + else if (not_full != selected_in_curr_leg) { + return -1; + } + /* Extrusion area starts/ends if met. */ + if (selected_in_prev_leg != selected_in_curr_leg) { + copy_intervals[ins] = selected_in_curr_leg == max_i || j == 0 ? j : j - 1; + ins++; + selected_in_prev_leg = selected_in_curr_leg; + } + copy_intervals[ins] = j; + } + if (selected_leg_count && + /* Prevents leading and trailing unselected legs if all selected. + * Unless it is extrusion from point or curve.*/ + (selected_leg_count < max_j || max_j == 1)) { + /* Prepend unselected leg if more than one leg selected at the starting edge. + * max_j == 1 handles extrusion from point to curve and from curve to surface cases. */ + if (is_first_sel && (copy_intervals[0] < copy_intervals[1] || max_j == 1)) { + memmove(copy_intervals + 1, copy_intervals, (ins + 1) * sizeof(copy_intervals[0])); + copy_intervals[0] = 0; + ins++; + is_first_sel = false; + } + /* Append unselected leg if more than one leg selected at the end. */ + if (is_last_sel && copy_intervals[ins - 1] < copy_intervals[ins]) { + copy_intervals[ins + 1] = copy_intervals[ins]; + ins++; + } + } + *interval_count = ins; + *out_is_first_sel = ins > 1 ? is_first_sel : false; + return selected_leg_count; +} - if (ELEM(u, 0, nu->pntsv - 1)) { /* row in u-direction selected */ - ok = true; - newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) * sizeof(BPoint), - "extrudeNurb1"); - if (u == 0) { - len = nu->pntsv * nu->pntsu; - ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len); - ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu); - bp = newbp; - } - else { - len = nu->pntsv * nu->pntsu; - ED_curve_bpcpy(editnurb, newbp, nu->bp, len); - ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu); - bp = newbp + len; - } +typedef struct NurbDim { + int pntsu; + int pntsv; +} NurbDim; - a = nu->pntsu; - while (a--) { - select_bpoint(bp, SELECT, flag, HIDDEN); - bp++; - } +static NurbDim editnurb_find_max_points_num(const EditNurb *editnurb) +{ + NurbDim ret = {0, 0}; + LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) { + if (nu->pntsu > ret.pntsu) { + ret.pntsu = nu->pntsu; + } + if (nu->pntsv > ret.pntsv) { + ret.pntsv = nu->pntsv; + } + } + return ret; +} - MEM_freeN(nu->bp); - nu->bp = newbp; - nu->pntsv++; - BKE_nurb_knot_calc_v(nu); - } - else if (ELEM(v, 0, nu->pntsu - 1)) { /* column in v-direction selected */ - ok = true; - bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), - "extrudeNurb1"); - bp = nu->bp; +bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag) +{ + const NurbDim max = editnurb_find_max_points_num(editnurb); + /* One point induces at most one interval. Except single point case, it can give + 1. + * Another +1 is for first element of the first interval. */ + int *const intvls_u = MEM_malloc_arrayN(max.pntsu + 2, sizeof(int), "extrudeNurb0"); + int *const intvls_v = MEM_malloc_arrayN(max.pntsv + 2, sizeof(int), "extrudeNurb1"); + bool ok = false; - for (a = 0; a < nu->pntsv; a++) { - if (v == 0) { - *bpn = *bp; - bpn->f1 |= flag; - bpn++; - } - ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu); - bp += nu->pntsu; - bpn += nu->pntsu; - if (v == nu->pntsu - 1) { - *bpn = *(bp - 1); - bpn->f1 |= flag; - bpn++; - } - } + LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) { + int intvl_cnt_u; + bool is_first_sel_u; - MEM_freeN(nu->bp); - nu->bp = newbp; - nu->pntsu++; - BKE_nurb_knot_calc_u(nu); - } - } + /* Calculate selected U legs and intervals for their extrusion. */ + const int selected_us = sel_to_copy_ints( + nu->bp, 1, nu->pntsu, nu->pntsu, nu->pntsv, flag, intvls_u, &intvl_cnt_u, &is_first_sel_u); + if (selected_us == -1) { + continue; } - } + int intvl_cnt_v; + bool is_first_sel_v; + const bool is_point = nu->pntsu == 1; + const bool is_curve = nu->pntsv == 1; + const bool extrude_every_u_point = selected_us == nu->pntsu; + if (is_point || (is_curve && !extrude_every_u_point)) { + intvls_v[0] = intvls_v[1] = 0; + intvl_cnt_v = 1; + is_first_sel_v = false; + } + else { + sel_to_copy_ints(nu->bp, + nu->pntsu, + nu->pntsv, + 1, + nu->pntsu, + flag, + intvls_v, + &intvl_cnt_v, + &is_first_sel_v); + } + + const int new_pntsu = nu->pntsu + intvl_cnt_u - 1; + const int new_pntsv = nu->pntsv + intvl_cnt_v - 1; + BPoint *const new_bp = (BPoint *)MEM_malloc_arrayN( + new_pntsu * new_pntsv, sizeof(BPoint), "extrudeNurb2"); + BPoint *new_bp_v = new_bp; + + bool selected_v = is_first_sel_v; + for (int j = 1; j <= intvl_cnt_v; j++, selected_v = !selected_v) { + BPoint *old_bp_v = nu->bp + intvls_v[j - 1] * nu->pntsu; + for (int v_j = intvls_v[j - 1]; v_j <= intvls_v[j]; + v_j++, new_bp_v += new_pntsu, old_bp_v += nu->pntsu) { + BPoint *new_bp_u_v = new_bp_v; + bool selected_u = is_first_sel_u; + for (int i = 1; i <= intvl_cnt_u; i++, selected_u = !selected_u) { + const int copy_from = intvls_u[i - 1]; + const int copy_to = intvls_u[i]; + const int copy_count = copy_to - copy_from + 1; + const bool sel_status = selected_u || selected_v ? SELECT : DESELECT; + ED_curve_bpcpy(editnurb, new_bp_u_v, old_bp_v + copy_from, copy_count); + select_bpoints(new_bp_u_v, 1, copy_count, sel_status, flag, HIDDEN); + new_bp_u_v += copy_count; + } + } + } + + MEM_freeN(nu->bp); + nu->bp = new_bp; + nu->pntsu = new_pntsu; + if (nu->pntsv == 1 && new_pntsv > 1) { + nu->orderv = 2; + } + nu->pntsv = new_pntsv; + BKE_nurb_knot_calc_u(nu); + BKE_nurb_knot_calc_v(nu); + + ok = true; + } + MEM_freeN(intvls_u); + MEM_freeN(intvls_v); return ok; } @@ -5695,23 +5716,12 @@ static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op)) Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; bool changed = false; - bool as_curve = false; if (!ED_curve_select_check(v3d, cu->editnurb)) { continue; } - /* First test: curve? */ - if (obedit->type != OB_CURVES_LEGACY) { - LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) { - if ((nu->pntsv == 1) && (ED_curve_nurb_select_count(v3d, nu) < nu->pntsu)) { - as_curve = true; - break; - } - } - } - - if (obedit->type == OB_CURVES_LEGACY || as_curve) { + if (obedit->type == OB_CURVES_LEGACY) { changed = ed_editcurve_extrude(cu, editnurb, v3d); } else { diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index 303d2fb71dc..945bba0a77c 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -13,6 +13,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index e0c440b09b4..6e28bb3e8ec 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -10,6 +10,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh ) set(INC_SYS diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 09a3cac0d48..9cb9e7ca1af 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -14,6 +14,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index b73b62d5a9d..9d3fd5af47f 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -144,6 +144,7 @@ void BM_uv_element_map_free(struct UvElementMap *element_map); struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l); +struct UvElement *BM_uv_element_get_head(struct UvElementMap *map, struct UvElement *child); /** * Can we edit UV's for this mesh? @@ -552,16 +553,10 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum); bool ED_mesh_color_ensure(struct Mesh *me, const char *name); int ED_mesh_color_add( struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports); -bool ED_mesh_color_remove_index(struct Mesh *me, int n); -bool ED_mesh_color_remove_active(struct Mesh *me); -bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); - -bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name); -int ED_mesh_sculpt_color_add( - struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports); -bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n); -bool ED_mesh_sculpt_color_remove_active(struct Mesh *me); -bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name); +int ED_mesh_sculpt_color_add(struct Mesh *me, + const char *name, + bool do_init, + struct ReportList *reports); void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail); void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 80a75da27f8..24d6819536d 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -305,6 +305,29 @@ void ED_uvedit_buttons_register(struct ARegionType *art); /* uvedit_islands.c */ +struct FaceIsland { + struct FaceIsland *next; + struct FaceIsland *prev; + struct BMFace **faces; + int faces_len; + rctf bounds_rect; + /** + * \note While this is duplicate information, + * it allows islands from multiple meshes to be stored in the same list. + */ + uint cd_loop_uv_offset; + float aspect_y; +}; + +int bm_mesh_calc_uv_islands(const Scene *scene, + struct BMesh *bm, + ListBase *island_list, + const bool only_selected_faces, + const bool only_selected_uvs, + const bool use_seams, + const float aspect_y, + const uint cd_loop_uv_offset); + struct UVMapUDIM_Params { const struct Image *image; /** Copied from #SpaceImage.tile_grid_shape */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a8d25b75036..163ea7e9493 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -85,7 +85,7 @@ typedef struct uiViewItemHandle uiViewItemHandle; /* Separator for text in search menus (right pointing arrow). * keep in sync with `string_search.cc`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" /* names */ #define UI_MAX_DRAW_STR 400 @@ -2482,7 +2482,7 @@ enum uiTemplateListFlags { ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST); void uiTemplateList(uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, @@ -2496,7 +2496,7 @@ void uiTemplateList(uiLayout *layout, int columns, enum uiTemplateListFlags flags); struct uiList *uiTemplateList_ex(uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, @@ -2566,7 +2566,7 @@ enum { UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2), }; void uiTemplateAssetView(struct uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *list_id, struct PointerRNA *asset_library_dataptr, const char *asset_library_propname, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 07c3bfdafbf..e4a973a375e 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -21,21 +21,22 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) set(SRC - eyedroppers/interface_eyedropper.c eyedroppers/eyedropper_color.c eyedroppers/eyedropper_colorband.c eyedroppers/eyedropper_datablock.c eyedroppers/eyedropper_depth.c eyedroppers/eyedropper_driver.c eyedroppers/eyedropper_gpencil_color.c + eyedroppers/interface_eyedropper.c interface.cc interface_align.c - interface_anim.c + interface_anim.cc interface_button_group.c interface_context_menu.c interface_context_path.cc @@ -46,8 +47,8 @@ set(SRC interface_icons.c interface_icons_event.c interface_layout.c - interface_ops.c - interface_panel.c + interface_ops.cc + interface_panel.cc interface_query.cc interface_region_color_picker.cc interface_region_hud.cc @@ -56,16 +57,16 @@ set(SRC interface_region_popover.cc interface_region_popup.cc interface_region_search.cc - interface_region_tooltip.c + interface_region_tooltip.cc interface_regions.cc interface_style.cc interface_template_asset_view.cc interface_template_attribute_search.cc interface_template_list.cc interface_template_search_menu.cc - interface_template_search_operator.c + interface_template_search_operator.cc interface_templates.c - interface_undo.c + interface_undo.cc interface_utils.cc interface_widgets.c resources.c @@ -82,7 +83,7 @@ set(SRC eyedroppers/eyedropper_intern.h interface_intern.h - interface_regions_intern.h + interface_regions_intern.hh ) set(LIB diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.cc index d7d1d3ce260..8e898b7fe66 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.cc @@ -4,9 +4,9 @@ * \ingroup edinterface */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -49,8 +49,14 @@ static FCurve *ui_but_get_fcurve( * but works well enough in typical cases */ const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex; - return BKE_fcurve_find_by_rna_context_ui( - but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special); + return BKE_fcurve_find_by_rna_context_ui(static_cast<bContext *>(but->block->evil_C), + &but->rnapoin, + but->rnaprop, + rnaindex, + adt, + action, + r_driven, + r_special); } void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) @@ -93,7 +99,7 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) } /* XXX: this feature is totally broken and useless with NLA */ - if (adt == NULL || adt->nla_tracks.first == NULL) { + if (adt == nullptr || adt->nla_tracks.first == nullptr) { const AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct_at( anim_eval_context, cfra); if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) { @@ -109,13 +115,13 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate) { - uiBut *but_iter = NULL; + uiBut *but_iter = nullptr; BLI_assert(UI_but_is_decorator(&but_decorate->but)); BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop); LISTBASE_CIRCULAR_BACKWARD_BEGIN ( - &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { + uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { if (but_iter != (uiBut *)but_decorate && ui_but_rna_equals_ex( but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) { @@ -123,9 +129,9 @@ static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_deco } } LISTBASE_CIRCULAR_BACKWARD_END( - &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev); + uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev); - return NULL; + return nullptr; } void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but) @@ -173,7 +179,7 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) ChannelDriver *driver; bool driven, special; - fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special); + fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special); if (fcu && driven) { driver = fcu->driver; @@ -195,13 +201,13 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) ChannelDriver *driver; bool driven, special; - fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special); + fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special); if (fcu && driven) { driver = fcu->driver; if (driver && (driver->type == DRIVER_TYPE_PYTHON)) { - bContext *C = but->block->evil_C; + bContext *C = static_cast<bContext *>(but->block->evil_C); BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression)); @@ -213,7 +219,7 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) fcu->flag &= ~FCURVE_DISABLED; /* this notifier should update the Graph Editor and trigger depsgraph refresh? */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr); DEG_relations_tag_update(CTX_data_main(C)); @@ -226,14 +232,14 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) bool ui_but_anim_expression_create(uiBut *but, const char *str) { - bContext *C = but->block->evil_C; + bContext *C = static_cast<bContext *>(but->block->evil_C); ID *id; FCurve *fcu; char *path; bool ok = false; /* button must have RNA-pointer to a numeric-capable property */ - if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) { + if (ELEM(nullptr, but->rnapoin.data, but->rnaprop)) { if (G.debug & G_DEBUG) { printf("ERROR: create expression failed - button has no RNA info attached\n"); } @@ -253,7 +259,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* FIXME: until materials can be handled by depsgraph, * don't allow drivers to be created for them */ id = but->rnapoin.owner_id; - if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { + if ((id == nullptr) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { if (G.debug & G_DEBUG) { printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id); } @@ -262,7 +268,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* get path */ path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); - if (path == NULL) { + if (path == nullptr) { return false; } @@ -282,7 +288,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* updates */ BKE_driver_invalidate_expression(driver, true, false); DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr); ok = true; } } @@ -300,19 +306,19 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) void ui_but_anim_copy_driver(bContext *C) { /* this operator calls UI_context_active_but_prop_get */ - WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } void ui_but_anim_paste_driver(bContext *C) { /* this operator calls UI_context_active_but_prop_get */ - WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)) { wmWindowManager *wm = CTX_wm_manager(C); - uiButDecorator *but_decorate = arg_but; + uiButDecorator *but_decorate = static_cast<uiButDecorator *>(arg_but); uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate); if (!but_anim) { @@ -332,7 +338,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr); WM_operator_properties_free(&props_ptr); } else { @@ -340,7 +346,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr); WM_operator_properties_free(&props_ptr); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 03b9d03a6e3..d75d86c2665 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -468,6 +468,7 @@ typedef enum uiButtonGroupFlag { /** The buttons in this group are inside a panel header. */ UI_BUTTON_GROUP_PANEL_HEADER = (1 << 1), } uiButtonGroupFlag; +ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER); struct uiBlock { uiBlock *next, *prev; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.cc index 4a5919864c7..2533a5454a5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.cc @@ -5,7 +5,7 @@ * \ingroup edinterface */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -128,7 +128,7 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *op) /* try to create driver using property retrieved from UI */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.owner_id != NULL) { + if (ptr.owner_id != nullptr) { if (full_path) { if (prop) { path = RNA_path_full_property_py_ex(bmain, &ptr, prop, index, true); @@ -217,7 +217,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op) if (ptr.owner_id && ptr.data && prop) { ID *id; - const int dim = RNA_property_array_dimension(&ptr, prop, NULL); + const int dim = RNA_property_array_dimension(&ptr, prop, nullptr); char *path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, dim, index, &id); if (path) { @@ -261,25 +261,25 @@ static bool copy_python_command_button_poll(bContext *C) { uiBut *but = UI_context_active_but_get(C); - if (but && (but->optype != NULL)) { - return 1; + if (but && (but->optype != nullptr)) { + return true; } - return 0; + return false; } static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op)) { uiBut *but = UI_context_active_but_get(C); - if (but && (but->optype != NULL)) { + if (but && (but->optype != nullptr)) { PointerRNA *opptr; char *str; opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ - str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr); + str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr); - WM_clipboard_text_set(str, 0); + WM_clipboard_text_set(str, false); MEM_freeN(str); @@ -391,7 +391,8 @@ static void UI_OT_reset_default_button(wmOperatorType *ot) ot->flag = 0; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); } /** \} */ @@ -530,7 +531,7 @@ static EnumPropertyItem override_type_items[] = { 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static bool override_type_set_button_poll(bContext *C) @@ -581,16 +582,16 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op) /* try to reset the nominated setting to its default value */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); - BLI_assert(ptr.owner_id != NULL); + BLI_assert(ptr.owner_id != nullptr); if (all) { index = -1; } IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_get( - CTX_data_main(C), &ptr, prop, operation, index, true, NULL, &created); + CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created); - if (opop == NULL) { + if (opop == nullptr) { /* Sometimes e.g. RNA cannot generate a path to the given property. */ BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation"); return OPERATOR_CANCELLED; @@ -601,7 +602,7 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op) } /* Outliner e.g. has to be aware of this change. */ - WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr); return operator_button_property_finish(C, &ptr, prop); } @@ -634,7 +635,8 @@ static void UI_OT_override_type_set_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, @@ -671,8 +673,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) ID *id = ptr.owner_id; IDOverrideLibraryProperty *oprop = RNA_property_override_property_find(bmain, &ptr, prop, &id); - BLI_assert(oprop != NULL); - BLI_assert(id != NULL && id->override_library != NULL); + BLI_assert(oprop != nullptr); + BLI_assert(id != nullptr && id->override_library != nullptr); const bool is_template = ID_IS_OVERRIDE_LIBRARY_TEMPLATE(id); @@ -691,8 +693,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) /* Remove override operation for given item, * add singular operations for the other items as needed. */ IDOverrideLibraryPropertyOperation *opop = BKE_lib_override_library_property_operation_find( - oprop, NULL, NULL, index, index, false, &is_strict_find); - BLI_assert(opop != NULL); + oprop, nullptr, nullptr, index, index, false, &is_strict_find); + BLI_assert(opop != nullptr); if (!is_strict_find) { /* No specific override operation, we have to get generic one, * and create item-specific override operations for all but given index, @@ -700,7 +702,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) for (int idx = RNA_property_array_length(&ptr, prop); idx--;) { if (idx != index) { BKE_lib_override_library_property_operation_get( - oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL); + oprop, opop->operation, nullptr, nullptr, idx, idx, true, nullptr, nullptr); } } } @@ -721,7 +723,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) } /* Outliner e.g. has to be aware of this change. */ - WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr); return operator_button_property_finish(C, &ptr, prop); } @@ -741,7 +743,8 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); } /** \} */ @@ -750,8 +753,8 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) /** \name Copy To Selected Operator * \{ */ -#define NOT_NULL(assignment) ((assignment) != NULL) -#define NOT_RNA_NULL(assignment) ((assignment).data != NULL) +#define NOT_NULL(assignment) ((assignment) != nullptr) +#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr) static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb) { @@ -760,7 +763,7 @@ static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb) if (!BLI_listbase_is_empty(&lb)) { LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) { - bPoseChannel *pchan = link->ptr.data; + bPoseChannel *pchan = static_cast<bPoseChannel *>(link->ptr.data); RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr); } } @@ -776,9 +779,9 @@ bool UI_context_copy_to_selected_list(bContext *C, char **r_path) { *r_use_path_from_id = false; - *r_path = NULL; + *r_path = nullptr; /* special case for bone constraints */ - char *path_from_bone = NULL; + char *path_from_bone = nullptr; /* Remove links from the collection list which don't contain 'prop'. */ bool ensure_list_items_contain_prop = false; @@ -792,29 +795,32 @@ bool UI_context_copy_to_selected_list(bContext *C, */ if (!RNA_property_is_idprop(prop) && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { PointerRNA owner_ptr; - char *idpath = NULL; + char *idpath = nullptr; /* First, check the active PoseBone and PoseBone->Bone. */ if (NOT_RNA_NULL( owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone))) { - if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else { - bPoseChannel *pchan = owner_ptr.data; + bPoseChannel *pchan = static_cast<bPoseChannel *>(owner_ptr.data); RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone, &owner_ptr); - if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { ui_context_selected_bones_via_pose(C, r_lb); } } } - if (idpath == NULL) { + if (idpath == nullptr) { /* Check the active EditBone if in edit mode. */ if (NOT_RNA_NULL( owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) && - NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); } @@ -867,30 +873,30 @@ bool UI_context_copy_to_selected_list(bContext *C, } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) && (path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) != - NULL) { + nullptr) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); *r_path = path_from_bone; } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { - ListBase lb = {NULL, NULL}; - char *path = NULL; - bNode *node = NULL; + ListBase lb = {nullptr, nullptr}; + char *path = nullptr; + bNode *node = nullptr; /* Get the node we're editing */ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNodeSocket *sock = ptr->data; - if (nodeFindNode(ntree, sock, &node, NULL)) { - if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) { + bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data); + if (nodeFindNode(ntree, sock, &node, nullptr)) { + if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != nullptr) { /* we're good! */ } else { - node = NULL; + node = nullptr; } } } else { - node = ptr->data; + node = static_cast<bNode *>(ptr->data); } /* Now filter by type */ @@ -898,7 +904,7 @@ bool UI_context_copy_to_selected_list(bContext *C, lb = CTX_data_collection_get(C, "selected_nodes"); LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) { - bNode *node_data = link->ptr.data; + bNode *node_data = static_cast<bNode *>(link->ptr.data); if (node_data->type != node->type) { BLI_remlink(&lb, link); @@ -929,17 +935,17 @@ bool UI_context_copy_to_selected_list(bContext *C, LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) { Object *ob = (Object *)link->ptr.owner_id; if (ob->data) { - ID *id_data = ob->data; + ID *id_data = static_cast<ID *>(ob->data); id_data->tag |= LIB_TAG_DOIT; } } LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) { Object *ob = (Object *)link->ptr.owner_id; - ID *id_data = ob->data; + ID *id_data = static_cast<ID *>(ob->data); - if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || ID_IS_LINKED(id_data) || - (GS(id_data->name) != id_code)) { + if ((id_data == nullptr) || (id_data->tag & LIB_TAG_DOIT) == 0 || + ID_IS_LINKED(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); MEM_freeN(link); } @@ -961,7 +967,8 @@ bool UI_context_copy_to_selected_list(bContext *C, /* Sequencer's ID is scene :/ */ /* Try to recursively find an RNA_Sequence ancestor, * to handle situations like T41062... */ - if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != + nullptr) { /* Special case when we do this for 'Sequence.lock'. * (if the sequence is locked, it won't be in "selected_editable_sequences"). */ const char *prop_id = RNA_property_identifier(prop); @@ -975,7 +982,7 @@ bool UI_context_copy_to_selected_list(bContext *C, ensure_list_items_contain_prop = true; } } - return (*r_path != NULL); + return (*r_path != nullptr); } else { return false; @@ -1013,13 +1020,13 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, if (use_path_from_id) { /* Path relative to ID. */ - lprop = NULL; + lprop = nullptr; RNA_id_pointer_create(ptr_link->owner_id, &idptr); RNA_path_resolve_property(&idptr, path, &lptr, &lprop); } else if (path) { /* Path relative to elements from list. */ - lprop = NULL; + lprop = nullptr; RNA_path_resolve_property(ptr_link, path, &lptr, &lprop); } else { @@ -1034,7 +1041,7 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, /* Skip non-existing properties on link. This was previously covered with the `lprop != prop` * check but we are now more permissive when it comes to ID properties, see below. */ - if (lprop == NULL) { + if (lprop == nullptr) { return false; } @@ -1105,13 +1112,13 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) UI_context_active_but_prop_get(C, &ptr, &prop, &index); /* if there is a valid property that is editable... */ - if (ptr.data == NULL || prop == NULL) { + if (ptr.data == nullptr || prop == nullptr) { return false; } - char *path = NULL; + char *path = nullptr; bool use_path_from_id; - ListBase lb = {NULL}; + ListBase lb = {nullptr}; if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) { return false; @@ -1198,7 +1205,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) /* Verify pointer type. */ char bone_name[MAXBONENAME]; - const StructRNA *target_type = NULL; + const StructRNA *target_type = nullptr; if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) { RNA_string_get(&ptr, "name", bone_name); @@ -1210,13 +1217,13 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) target_type = &RNA_Object; } - if (target_type == NULL) { + if (target_type == nullptr) { return false; } /* Find the containing Object. */ ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = NULL; + Base *base = nullptr; const short id_type = GS(ptr.owner_id->name); if (id_type == ID_OB) { base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id); @@ -1226,7 +1233,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) } bool ok = false; - if ((base == NULL) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) { + if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) { /* pass */ } else if (poll) { @@ -1278,13 +1285,14 @@ static bool jump_to_target_button(bContext *C, bool poll) if (type == PROP_STRING) { const uiBut *but = UI_context_active_but_get(C); const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but : - NULL; + nullptr; if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) { - uiRNACollectionSearch *coll_search = search_but->arg; + uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg); char str_buf[MAXBONENAME]; - char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL); + char *str_ptr = RNA_property_string_get_alloc( + &ptr, prop, str_buf, sizeof(str_buf), nullptr); int found = RNA_property_collection_lookup_string( &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr); @@ -1342,39 +1350,39 @@ static void UI_OT_jump_to_target_button(wmOperatorType *ot) /* EditSource Utility funcs and operator, * NOTE: this includes utility functions and button matching checks. */ -typedef struct uiEditSourceStore { +struct uiEditSourceStore { uiBut but_orig; GHash *hash; -} uiEditSourceStore; +}; -typedef struct uiEditSourceButStore { +struct uiEditSourceButStore { char py_dbg_fn[FILE_MAX]; int py_dbg_line_number; -} uiEditSourceButStore; +}; /* should only ever be set while the edit source operator is running */ -static struct uiEditSourceStore *ui_editsource_info = NULL; +static uiEditSourceStore *ui_editsource_info = nullptr; bool UI_editsource_enable_check(void) { - return (ui_editsource_info != NULL); + return (ui_editsource_info != nullptr); } static void ui_editsource_active_but_set(uiBut *but) { - BLI_assert(ui_editsource_info == NULL); + BLI_assert(ui_editsource_info == nullptr); - ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__); + ui_editsource_info = MEM_cnew<uiEditSourceStore>(__func__); memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut)); ui_editsource_info->hash = BLI_ghash_ptr_new(__func__); } -static void ui_editsource_active_but_clear(void) +static void ui_editsource_active_but_clear() { - BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN); + BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN); MEM_freeN(ui_editsource_info); - ui_editsource_info = NULL; + ui_editsource_info = nullptr; } static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b) @@ -1395,11 +1403,14 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b) return false; } +extern "C" { +void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); +} + void UI_editsource_active_but_test(uiBut *but) { - extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); - struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__); + uiEditSourceButStore *but_store = MEM_cnew<uiEditSourceButStore>(__func__); const char *fn; int line_number = -1; @@ -1424,9 +1435,10 @@ void UI_editsource_active_but_test(uiBut *but) void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but) { - uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but); + uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>( + BLI_ghash_lookup(ui_editsource_info->hash, old_but)); if (but_store) { - BLI_ghash_remove(ui_editsource_info->hash, old_but, NULL, NULL); + BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr); BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store); } } @@ -1436,8 +1448,8 @@ static int editsource_text_edit(bContext *C, const char filepath[FILE_MAX], const int line) { - struct Main *bmain = CTX_data_main(C); - Text *text = NULL; + Main *bmain = CTX_data_main(C); + Text *text = nullptr; /* Developers may wish to copy-paste to an external editor. */ printf("%s:%d\n", filepath, line); @@ -1449,11 +1461,11 @@ static int editsource_text_edit(bContext *C, } } - if (text == NULL) { + if (text == nullptr) { text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain)); } - if (text == NULL) { + if (text == nullptr) { BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath); return OPERATOR_CANCELLED; } @@ -1477,7 +1489,7 @@ static int editsource_exec(bContext *C, wmOperator *op) if (but) { GHashIterator ghi; - struct uiEditSourceButStore *but_store = NULL; + uiEditSourceButStore *but_store = nullptr; ARegion *region = CTX_wm_region(C); int ret; @@ -1496,9 +1508,9 @@ static int editsource_exec(bContext *C, wmOperator *op) for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash); BLI_ghashIterator_done(&ghi) == false; BLI_ghashIterator_step(&ghi)) { - uiBut *but_key = BLI_ghashIterator_getKey(&ghi); + uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi)); if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) { - but_store = BLI_ghashIterator_getValue(&ghi); + but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi)); break; } } @@ -1569,7 +1581,7 @@ static void edittranslation_find_po_file(const char *root, /* Now try without the second iso code part (_ES in es_ES). */ { - const char *tc = NULL; + const char *tc = nullptr; size_t szt = 0; tstr[0] = '\0'; @@ -1603,7 +1615,7 @@ static void edittranslation_find_po_file(const char *root, static int edittranslation_exec(bContext *C, wmOperator *op) { uiBut *but = UI_context_active_but_get(C); - if (but == NULL) { + if (but == nullptr) { BKE_report(op->reports, RPT_ERROR, "Active button not found"); return OPERATOR_CANCELLED; } @@ -1614,16 +1626,16 @@ static int edittranslation_exec(bContext *C, wmOperator *op) const char *root = U.i18ndir; const char *uilng = BLT_lang_get(); - uiStringInfo but_label = {BUT_GET_LABEL, NULL}; - uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; - uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL}; - uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL}; + uiStringInfo but_label = {BUT_GET_LABEL, nullptr}; + uiStringInfo rna_label = {BUT_GET_RNA_LABEL, nullptr}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr}; + uiStringInfo but_tip = {BUT_GET_TIP, nullptr}; + uiStringInfo rna_tip = {BUT_GET_RNA_TIP, nullptr}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr}; + uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, nullptr}; + uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, nullptr}; if (!BLI_is_dir(root)) { BKE_report(op->reports, @@ -1632,8 +1644,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op) "Directory' path to a valid directory"); return OPERATOR_CANCELLED; } - ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0); - if (ot == NULL) { + ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, false); + if (ot == nullptr) { BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on " @@ -1662,7 +1674,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) &rna_prop, &rna_enum, &rna_ctxt, - NULL); + nullptr); WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "lang", uilng); @@ -1677,7 +1689,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo); RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo); RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo); - const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); + const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); /* Clean up */ if (but_label.strinfo) { @@ -1737,7 +1749,7 @@ static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { BLT_lang_init(); BLF_cache_clear(); - BLT_lang_set(NULL); + BLT_lang_set(nullptr); UI_reinit_font(); return OPERATOR_FINISHED; } @@ -1764,13 +1776,13 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev bScreen *screen = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *region_prev = CTX_wm_region(C); - ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL; + ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr; - if (region == NULL) { + if (region == nullptr) { region = region_prev; } - if (region == NULL) { + if (region == nullptr) { return OPERATOR_PASS_THROUGH; } @@ -1778,7 +1790,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev uiBut *but = UI_context_active_but_get(C); CTX_wm_region_set(C, region_prev); - if (but == NULL) { + if (but == nullptr) { return OPERATOR_PASS_THROUGH; } if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) { @@ -1791,7 +1803,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev UI_but_execute(C, region, but); - but->optype = but_optype; + but->optype = static_cast<wmOperatorType *>(but_optype); WM_event_add_mousemove(CTX_wm_window(C)); @@ -1807,7 +1819,7 @@ static void UI_OT_button_execute(wmOperatorType *ot) ot->invoke = ui_button_press_invoke; ot->flag = OPTYPE_INTERNAL; - RNA_def_boolean(ot->srna, "skip_depressed", 0, "Skip Depressed", ""); + RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", ""); } /** \} */ @@ -1853,21 +1865,21 @@ bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED( ARegion *region = CTX_wm_region(C); if (UI_but_active_drop_color(C)) { - return 1; + return true; } if (sima && (sima->mode == SI_MODE_PAINT) && sima->image && (region && region->regiontype == RGN_TYPE_WINDOW)) { - return 1; + return true; } } - return 0; + return false; } void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { - uiDragColorHandle *drag_info = drag->poin; + uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin); RNA_float_set_array(drop->ptr, "color", drag_info->color); RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected); @@ -1876,7 +1888,7 @@ void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *region = CTX_wm_region(C); - uiBut *but = NULL; + uiBut *but = nullptr; float color[4]; bool gamma; @@ -1933,8 +1945,10 @@ static void UI_OT_drop_color(wmOperatorType *ot) ot->invoke = drop_color_invoke; ot->flag = OPTYPE_INTERNAL; - RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); - RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected"); + RNA_def_float_color( + ot->srna, "color", 3, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); + RNA_def_boolean( + ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected"); } /** \} */ @@ -1964,7 +1978,7 @@ static bool drop_name_poll(bContext *C) static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiBut *but = UI_but_active_drop_name_button(C); - char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL); + char *str = RNA_string_get_alloc(op->ptr, "string", nullptr, 0, nullptr); if (str) { ui_but_set_string_interactive(C, but, str); @@ -1985,7 +1999,7 @@ static void UI_OT_drop_name(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string( - ot->srna, "string", NULL, 0, "String", "The string value to drop into the button"); + ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button"); } /** \} */ @@ -2003,7 +2017,7 @@ static bool ui_list_focused_poll(bContext *C) const wmWindow *win = CTX_wm_window(C); const uiList *list = UI_list_find_mouse_over(region, win->eventstate); - return list != NULL; + return list != nullptr; } /** @@ -2026,7 +2040,7 @@ static int ui_list_start_filter_invoke(bContext *C, wmOperator *UNUSED(op), cons ARegion *region = CTX_wm_region(C); uiList *list = UI_list_find_mouse_over(region, event); /* Poll should check. */ - BLI_assert(list != NULL); + BLI_assert(list != nullptr); if (ui_list_unhide_filter_options(list)) { ui_region_redraw_immediately(C, region); @@ -2061,7 +2075,7 @@ static bool ui_view_drop_poll(bContext *C) const ARegion *region = CTX_wm_region(C); const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, win->eventstate->xy); - return hovered_item != NULL; + return hovered_item != nullptr; } static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -2073,7 +2087,8 @@ static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven const ARegion *region = CTX_wm_region(C); uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy); - if (!UI_view_item_drop_handle(C, hovered_item, event->customdata)) { + if (!UI_view_item_drop_handle( + C, hovered_item, static_cast<const ListBase *>(event->customdata))) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -2107,7 +2122,7 @@ static bool ui_view_item_rename_poll(bContext *C) { const ARegion *region = CTX_wm_region(C); const uiViewItemHandle *active_item = UI_region_views_find_active_item(region); - return active_item != NULL && UI_view_item_can_rename(active_item); + return active_item != nullptr && UI_view_item_can_rename(active_item); } static int ui_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op)) @@ -2144,8 +2159,8 @@ static void UI_OT_view_item_rename(wmOperatorType *ot) static bool ui_drop_material_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object); - Object *ob = ptr.data; - if (ob == NULL) { + const Object *ob = static_cast<const Object *>(ptr.data); + if (ob == nullptr) { return false; } @@ -2163,12 +2178,12 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op) Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid( bmain, op->ptr, ID_MA); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object); - Object *ob = ptr.data; + Object *ob = static_cast<Object *>(ptr.data); BLI_assert(ob); PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot); @@ -2176,14 +2191,14 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op) const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1; /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) { + if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) { return OPERATOR_CANCELLED; } BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.cc index d4a9a4ca4cd..dc6a0fecb73 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.cc @@ -8,10 +8,10 @@ /* a full doc with API notes can be found in * bf-blender/trunk/blender/doc/guides/interface_API.txt */ -#include <ctype.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cctype> +#include <cmath> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -57,7 +57,7 @@ #define ANIMATION_TIME 0.30 #define ANIMATION_INTERVAL 0.02 -typedef enum uiPanelRuntimeFlag { +enum uiPanelRuntimeFlag { PANEL_LAST_ADDED = (1 << 0), PANEL_ACTIVE = (1 << 2), PANEL_WAS_ACTIVE = (1 << 3), @@ -78,22 +78,22 @@ typedef enum uiPanelRuntimeFlag { PANEL_IS_DRAG_DROP = (1 << 10), /** Draw a border with the active color around the panel. */ PANEL_ACTIVE_BORDER = (1 << 11), -} uiPanelRuntimeFlag; +}; /* The state of the mouse position relative to the panel. */ -typedef enum uiPanelMouseState { +enum uiPanelMouseState { PANEL_MOUSE_OUTSIDE, /** Mouse is not in the panel. */ PANEL_MOUSE_INSIDE_CONTENT, /** Mouse is in the actual panel content. */ PANEL_MOUSE_INSIDE_HEADER, /** Mouse is in the panel header. */ -} uiPanelMouseState; +}; -typedef enum uiHandlePanelState { +enum uiHandlePanelState { PANEL_STATE_DRAG, PANEL_STATE_ANIMATION, PANEL_STATE_EXIT, -} uiHandlePanelState; +}; -typedef struct uiHandlePanelData { +struct uiHandlePanelData { uiHandlePanelState state; /* Animation. */ @@ -104,17 +104,17 @@ typedef struct uiHandlePanelData { int startx, starty; int startofsx, startofsy; float start_cur_xmin, start_cur_ymin; -} uiHandlePanelData; +}; -typedef struct PanelSort { +struct PanelSort { Panel *panel; int new_offset_x; int new_offset_y; -} PanelSort; +}; static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel); static int get_panel_real_size_y(const Panel *panel); -static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); +static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state); static int compare_panel(const void *a, const void *b); static bool panel_type_context_poll(ARegion *region, const PanelType *panel_type, @@ -155,7 +155,7 @@ static bool panel_active_animation_changed(ListBase *lb, /* Detect animation. */ if (panel->activedata) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); if (data->state == PANEL_STATE_ANIMATION) { *r_panel_animation = panel; } @@ -178,7 +178,7 @@ static bool panel_active_animation_changed(ListBase *lb, static bool properties_space_needs_realign(const ScrArea *area, const ARegion *region) { if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) { - SpaceProperties *sbuts = area->spacedata.first; + const SpaceProperties *sbuts = static_cast<SpaceProperties *>(area->spacedata.first); if (sbuts->mainbo != sbuts->mainb) { return true; @@ -190,14 +190,14 @@ static bool properties_space_needs_realign(const ScrArea *area, const ARegion *r static bool panels_need_realign(const ScrArea *area, ARegion *region, Panel **r_panel_animation) { - *r_panel_animation = NULL; + *r_panel_animation = nullptr; if (properties_space_needs_realign(area, region)) { return true; } /* Detect if a panel was added or removed. */ - Panel *panel_animation = NULL; + Panel *panel_animation = nullptr; bool no_animation = false; if (panel_active_animation_changed(®ion->panels, &panel_animation, &no_animation)) { return true; @@ -225,7 +225,7 @@ static Panel *panel_add_instanced(ARegion *region, PanelType *panel_type, PointerRNA *custom_data) { - Panel *panel = MEM_callocN(sizeof(Panel), __func__); + Panel *panel = MEM_cnew<Panel>(__func__); panel->type = panel_type; BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); @@ -235,7 +235,7 @@ static Panel *panel_add_instanced(ARegion *region, /* Add the panel's children too. Although they aren't instanced panels, we can still use this * function to create them, as UI_panel_begin does other things we don't need to do. */ LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { - PanelType *child_type = child->data; + PanelType *child_type = static_cast<PanelType *>(child->data); panel_add_instanced(region, &panel->children, child_type, custom_data); } @@ -265,12 +265,12 @@ Panel *UI_panel_add_instanced(const bContext *C, { ARegionType *region_type = region->type; - PanelType *panel_type = BLI_findstring( - ®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname)); + PanelType *panel_type = static_cast<PanelType *>( + BLI_findstring(®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname))); - if (panel_type == NULL) { + if (panel_type == nullptr) { printf("Panel type '%s' not found.\n", panel_idname); - return NULL; + return nullptr; } Panel *new_panel = panel_add_instanced(region, panels, panel_type, custom_data); @@ -314,14 +314,14 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region) { /* Delete panels with the instanced flag. */ LISTBASE_FOREACH_MUTABLE (Panel *, panel, ®ion->panels) { - if ((panel->type != NULL) && (panel->type->flag & PANEL_TYPE_INSTANCED)) { + if ((panel->type != nullptr) && (panel->type->flag & PANEL_TYPE_INSTANCED)) { /* Make sure the panel's handler is removed before deleting it. */ - if (C != NULL && panel->activedata != NULL) { + if (C != nullptr && panel->activedata != nullptr) { panel_activate_state(C, panel, PANEL_STATE_EXIT); } /* Free panel's custom data. */ - if (panel->runtime.custom_data_ptr != NULL) { + if (panel->runtime.custom_data_ptr != nullptr) { MEM_freeN(panel->runtime.custom_data_ptr); } @@ -335,28 +335,28 @@ bool UI_panel_list_matches_data(ARegion *region, ListBase *data, uiListPanelIDFromDataFunc panel_idname_func) { - /* Check for NULL data. */ + /* Check for nullptr data. */ int data_len = 0; - Link *data_link = NULL; - if (data == NULL) { + Link *data_link = nullptr; + if (data == nullptr) { data_len = 0; - data_link = NULL; + data_link = nullptr; } else { data_len = BLI_listbase_count(data); - data_link = data->first; + data_link = static_cast<Link *>(data->first); } int i = 0; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { - if (panel->type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) { + if (panel->type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) { /* The panels were reordered by drag and drop. */ if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) { return false; } /* We reached the last data item before the last instanced panel. */ - if (data_link == NULL) { + if (data_link == nullptr) { return false; } @@ -383,15 +383,15 @@ bool UI_panel_list_matches_data(ARegion *region, static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel) { /* Without a type we cannot access the reorder callback. */ - if (drag_panel->type == NULL) { + if (drag_panel->type == nullptr) { return; } /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */ - if (drag_panel->type->reorder == NULL) { + if (drag_panel->type->reorder == nullptr) { return; } - char *context = NULL; + char *context = nullptr; if (!UI_panel_category_is_visible(region)) { context = drag_panel->type->context; } @@ -415,7 +415,8 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr BLI_assert(start_index != -1); /* The drag panel should definitely be in the list. */ /* Sort the matching instanced panels by their display order. */ - PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__); + PanelSort *panel_sort = static_cast<PanelSort *>( + MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__)); PanelSort *sort_index = panel_sort; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type) { @@ -452,7 +453,7 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr /* Finally, move this panel's list item to the new index in its list. */ drag_panel->type->reorder(C, drag_panel, move_to_index); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); } /** @@ -480,9 +481,9 @@ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, */ static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel) { - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); BLI_assert(panel->type->flag & PANEL_TYPE_INSTANCED); - if (panel->type->get_list_data_expand_flag == NULL) { + if (panel->type->get_list_data_expand_flag == nullptr) { /* Instanced panel doesn't support loading expansion. */ return; } @@ -504,7 +505,7 @@ static void region_panels_set_expansion_from_list_data(const bContext *C, ARegio LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { PanelType *panel_type = panel->type; - if (panel_type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) { + if (panel_type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) { panel_set_expansion_from_list_data(C, panel); } } @@ -537,7 +538,7 @@ static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *r { LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { PanelType *panel_type = panel->type; - if (panel_type == NULL) { + if (panel_type == nullptr) { continue; } @@ -563,11 +564,11 @@ static bool panel_custom_data_active_get(const Panel *panel) { /* The caller should make sure the panel is active and has a type. */ BLI_assert(UI_panel_is_active(panel)); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); if (panel->type->active_property[0] != '\0') { PointerRNA *ptr = UI_panel_custom_data_get(panel); - if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + if (ptr != nullptr && !RNA_pointer_is_null(ptr)) { return RNA_boolean_get(ptr, panel->type->active_property); } } @@ -579,12 +580,12 @@ static void panel_custom_data_active_set(Panel *panel) { /* Since the panel is interacted with, it should be active and have a type. */ BLI_assert(UI_panel_is_active(panel)); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); if (panel->type->active_property[0] != '\0') { PointerRNA *ptr = UI_panel_custom_data_get(panel); - BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != NULL); - if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != nullptr); + if (ptr != nullptr && !RNA_pointer_is_null(ptr)) { RNA_boolean_set(ptr, panel->type->active_property, true); } } @@ -617,7 +618,7 @@ static void panel_set_runtime_flag_recursive(Panel *panel, short flag, bool valu static void panels_collapse_all(ARegion *region, const Panel *from_panel) { const bool has_category_tabs = UI_panel_category_is_visible(region); - const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; + const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : nullptr; const PanelType *from_pt = from_panel->type; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -659,7 +660,7 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt) return panel; } } - return NULL; + return nullptr; } Panel *UI_panel_begin( @@ -668,10 +669,10 @@ Panel *UI_panel_begin( Panel *panel_last; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; - const bool newpanel = (panel == NULL); + const bool newpanel = (panel == nullptr); if (newpanel) { - panel = MEM_callocN(sizeof(Panel), __func__); + panel = MEM_cnew<Panel>(__func__); panel->type = pt; BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname)); @@ -701,7 +702,7 @@ Panel *UI_panel_begin( /* If a new panel is added, we insert it right after the panel that was last added. * This way new panels are inserted in the right place between versions. */ - for (panel_last = lb->first; panel_last; panel_last = panel_last->next) { + for (panel_last = static_cast<Panel *>(lb->first); panel_last; panel_last = panel_last->next) { if (panel_last->runtime_flag & PANEL_LAST_ADDED) { BLI_remlink(lb, panel); BLI_insertlinkafter(lb, panel_last, panel); @@ -755,7 +756,7 @@ void UI_panel_header_buttons_end(Panel *panel) /* A button group should always be created in #UI_panel_header_buttons_begin. */ BLI_assert(!BLI_listbase_is_empty(&block->button_groups)); - uiButtonGroup *button_group = block->button_groups.last; + uiButtonGroup *button_group = static_cast<uiButtonGroup *>(block->button_groups.last); button_group->flag &= ~UI_BUTTON_GROUP_LOCK; @@ -770,7 +771,7 @@ void UI_panel_header_buttons_end(Panel *panel) /* Always add a new button group. Although this may result in many empty groups, without it, * new buttons in the panel body not protected with a #ui_block_new_button_group call would * end up in the panel header group. */ - ui_block_new_button_group(block, 0); + ui_block_new_button_group(block, (uiButtonGroupFlag)0); } } @@ -867,7 +868,7 @@ void ui_panel_tag_search_filter_match(Panel *panel) static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches) { - *filter_matches |= panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH; + *filter_matches |= bool(panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH); /* If the panel has no match we need to make sure that its children are too. */ if (!*filter_matches) { @@ -893,7 +894,7 @@ static void panel_set_expansion_from_search_filter_recursive(const bContext *C, { /* This has to run on inactive panels that may not have a type, * but we can prevent running on header-less panels in some cases. */ - if (panel->type == NULL || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) { + if (panel->type == nullptr || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) { SET_FLAG_FROM_TEST(panel->runtime_flag, use_search_closed, PANEL_USE_CLOSED_FROM_SEARCH); } @@ -926,9 +927,9 @@ static void region_panels_set_expansion_from_search_filter(const bContext *C, static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *parent_panel) { uiBlock *block = panel->runtime.block; - BLI_assert(block != NULL); + BLI_assert(block != nullptr); BLI_assert(block->active); - if (parent_panel != NULL && UI_panel_is_closed(parent_panel)) { + if (parent_panel != nullptr && UI_panel_is_closed(parent_panel)) { /* The parent panel is closed, so this panel can be completely removed. */ UI_block_set_search_only(block, true); LISTBASE_FOREACH (uiBut *, but, &block->buttons) { @@ -944,7 +945,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel * continue; } LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) { - uiBut *but = link->data; + uiBut *but = static_cast<uiBut *>(link->data); but->flag |= UI_HIDDEN; } } @@ -952,7 +953,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel * LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { if (child_panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(child_panel->runtime.block != NULL); + BLI_assert(child_panel->runtime.block != nullptr); panel_remove_invisible_layouts_recursive(child_panel, panel); } } @@ -962,8 +963,8 @@ static void region_panels_remove_invisible_layouts(ARegion *region) { LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(panel->runtime.block != NULL); - panel_remove_invisible_layouts_recursive(panel, NULL); + BLI_assert(panel->runtime.block != nullptr); + panel_remove_invisible_layouts_recursive(panel, nullptr); } } } @@ -1054,7 +1055,7 @@ static void panel_draw_highlight_border(const Panel *panel, const rcti *rect, const rcti *header_rect) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; if (is_subpanel) { return; } @@ -1064,18 +1065,15 @@ static void panel_draw_highlight_border(const Panel *panel, const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect; UI_draw_roundbox_corner_set(UI_CNR_ALL); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin; + box_rect.ymax = header_rect->ymax; + float color[4]; UI_GetThemeColor4fv(TH_SELECT_ACTIVE, color); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin, - .ymax = header_rect->ymax, - }, - false, - radius, - color); + UI_draw_roundbox_4fv(&box_rect, false, radius, color); } static void panel_draw_aligned_widgets(const uiStyle *style, @@ -1086,19 +1084,18 @@ static void panel_draw_aligned_widgets(const uiStyle *style, const bool show_background, const bool region_search_filter_active) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; const int header_height = BLI_rcti_size_y(header_rect); const int scaled_unit = round_fl_to_int(UI_UNIT_X / aspect); - /* Offset triangle and text to the right for subpanels. */ - const rcti widget_rect = { - .xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0), - .xmax = header_rect->xmax, - .ymin = header_rect->ymin, - .ymax = header_rect->ymax, - }; + /* Offset triangle and text to the right for sub-panels. */ + rcti widget_rect; + widget_rect.xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0); + widget_rect.xmax = header_rect->xmax; + widget_rect.ymin = header_rect->ymin; + widget_rect.ymax = header_rect->ymax; uchar title_color[4]; panel_title_color_get(panel, show_background, region_search_filter_active, title_color); @@ -1121,20 +1118,16 @@ static void panel_draw_aligned_widgets(const uiStyle *style, /* Draw text label. */ if (panel->drawname[0] != '\0') { - const rcti title_rect = { - .xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f, - .xmax = widget_rect.xmax, - .ymin = widget_rect.ymin - 2.0f / aspect, - .ymax = widget_rect.ymax, - }; - UI_fontstyle_draw(fontstyle, - &title_rect, - panel->drawname, - sizeof(panel->drawname), - title_color, - &(struct uiFontStyleDraw_Params){ - .align = UI_STYLE_TEXT_LEFT, - }); + rcti title_rect; + title_rect.xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f; + title_rect.xmax = widget_rect.xmax; + title_rect.ymin = widget_rect.ymin - 2.0f / aspect; + title_rect.ymax = widget_rect.ymax; + + uiFontStyleDraw_Params params{}; + params.align = UI_STYLE_TEXT_LEFT; + UI_fontstyle_draw( + fontstyle, &title_rect, panel->drawname, sizeof(panel->drawname), title_color, ¶ms); } /* Draw the pin icon. */ @@ -1177,7 +1170,7 @@ static void panel_draw_aligned_backdrop(const Panel *panel, const rcti *rect, const rcti *header_rect) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; const bool is_open = !UI_panel_is_closed(panel); if (is_subpanel && !is_open) { @@ -1197,16 +1190,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel, UI_draw_roundbox_corner_set(is_open ? UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT : UI_CNR_ALL); UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = rect->ymin, - .ymax = rect->ymax, - }, - true, - radius, - panel_backcolor); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = rect->ymin; + box_rect.ymax = rect->ymax; + UI_draw_roundbox_4fv(&box_rect, true, radius, panel_backcolor); } /* Panel header backdrops for non sub-panels. */ @@ -1217,16 +1206,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel, UI_draw_roundbox_corner_set(is_open ? UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT : UI_CNR_ALL); /* Change the width a little bit to line up with the sides. */ - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = header_rect->ymin, - .ymax = header_rect->ymax, - }, - true, - radius, - panel_headercolor); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = header_rect->ymin; + box_rect.ymax = header_rect->ymax; + UI_draw_roundbox_4fv(&box_rect, true, radius, panel_headercolor); } GPU_blend(GPU_BLEND_NONE); @@ -1247,7 +1232,7 @@ void ui_draw_aligned_panel(const uiStyle *style, rect->xmin, rect->xmax, rect->ymax, - rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f), + rect->ymax + (int)floor(PNL_HEADER / block->aspect + 0.001f), }; if (show_background) { @@ -1300,7 +1285,7 @@ bool UI_panel_should_show_background(const ARegion *region, const PanelType *pan void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) { // #define USE_FLAT_INACTIVE - const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); + const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT; View2D *v2d = ®ion->v2d; const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; @@ -1463,26 +1448,17 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) { /* Draw filled rectangle and outline for tab. */ UI_draw_roundbox_corner_set(roundboxtype); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax, - }, - true, - tab_curve_radius, - is_active ? theme_col_tab_active : theme_col_tab_inactive); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax, - }, - false, - tab_curve_radius, - theme_col_tab_outline); + rctf box_rect; + box_rect.xmin = rct->xmin; + box_rect.xmax = rct->xmax; + box_rect.ymin = rct->ymin; + box_rect.ymax = rct->ymax; + + UI_draw_roundbox_4fv(&box_rect, + true, + tab_curve_radius, + is_active ? theme_col_tab_active : theme_col_tab_inactive); + UI_draw_roundbox_4fv(&box_rect, false, tab_curve_radius, theme_col_tab_outline); /* Disguise the outline on one side to join the tab to the panel. */ pos = GPU_vertformat_attr_add( @@ -1502,7 +1478,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) if (do_scaletabs) { category_draw_len = BLF_width_to_strlen( - fontid, category_id_draw, category_draw_len, category_width, NULL); + fontid, category_id_draw, category_draw_len, category_width, nullptr); } BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f); @@ -1660,7 +1636,7 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { /* These panels should have types since they are currently displayed to the user. */ - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); active_panels_len++; } } @@ -1669,7 +1645,8 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra } /* Sort panels. */ - PanelSort *panel_sort = MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__); + PanelSort *panel_sort = static_cast<PanelSort *>( + MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__)); { PanelSort *ps = panel_sort; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -1791,7 +1768,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y) static void ui_do_animate(bContext *C, Panel *panel) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); ARegion *region = CTX_wm_region(C); float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; @@ -1856,7 +1833,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(panel->runtime.block != NULL); + BLI_assert(panel->runtime.block != nullptr); panel_calculate_size_recursive(region, panel); } } @@ -1892,7 +1869,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) #define DRAG_REGION_PAD (PNL_HEADER * 0.5) static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); ARegion *region = CTX_wm_region(C); /* Keep the drag position in the region with a small pad to keep the panel visible. */ @@ -1942,14 +1919,14 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, return PANEL_MOUSE_OUTSIDE; } -typedef struct uiPanelDragCollapseHandle { +struct uiPanelDragCollapseHandle { bool was_first_open; int xy_init[2]; -} uiPanelDragCollapseHandle; +}; static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata) { - uiPanelDragCollapseHandle *dragcol_data = userdata; + uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata); MEM_freeN(dragcol_data); } @@ -1960,11 +1937,11 @@ static void ui_panel_drag_collapse(const bContext *C, ARegion *region = CTX_wm_region(C); LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)}; - float xy_b_block[2] = {UNPACK2(xy_dst)}; + float xy_a_block[2] = {(float)dragcol_data->xy_init[0], (float)dragcol_data->xy_init[1]}; + float xy_b_block[2] = {(float)xy_dst[0], (float)xy_dst[1]}; Panel *panel = block->panel; - if (panel == NULL || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) { + if (panel == nullptr || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) { continue; } const int oldflag = panel->flag; @@ -2006,7 +1983,7 @@ static void ui_panel_drag_collapse(const bContext *C, static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata) { wmWindow *win = CTX_wm_window(C); - uiPanelDragCollapseHandle *dragcol_data = userdata; + uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata); short retval = WM_UI_HANDLER_CONTINUE; switch (event->type) { @@ -2037,7 +2014,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was { wmWindow *win = CTX_wm_window(C); const wmEvent *event = win->eventstate; - uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__); + uiPanelDragCollapseHandle *dragcol_data = MEM_new<uiPanelDragCollapseHandle>(__func__); dragcol_data->was_first_open = was_open; copy_v2_v2_int(dragcol_data->xy_init, event->xy); @@ -2066,10 +2043,10 @@ static void ui_handle_panel_header(const bContext *C, Panel *panel = block->panel; ARegion *region = CTX_wm_region(C); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER)); - const bool is_subpanel = (panel->type->parent != NULL); + const bool is_subpanel = (panel->type->parent != nullptr); const bool use_pin = UI_panel_category_is_visible(region) && UI_panel_can_be_pinned(panel); const bool show_pin = use_pin && (panel->flag & PNL_PIN); const bool show_drag = !is_subpanel; @@ -2102,8 +2079,8 @@ static void ui_handle_panel_header(const bContext *C, else { /* If a panel has sub-panels and it's open, toggle the expansion * of the sub-panels (based on the expansion of the first sub-panel). */ - Panel *first_child = panel->children.first; - BLI_assert(first_child != NULL); + Panel *first_child = static_cast<Panel *>(panel->children.first); + BLI_assert(first_child != nullptr); panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child)); panel->flag |= PNL_CLOSED; } @@ -2115,7 +2092,7 @@ static void ui_handle_panel_header(const bContext *C, ui_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel)); } - /* Set panel custom data (modifier) active when expanding subpanels, but not top-level + /* Set panel custom data (modifier) active when expanding sub-panels, but not top-level * panels to allow collapsing and expanding without setting the active element. */ if (is_subpanel) { panel_custom_data_active_set(panel); @@ -2157,13 +2134,14 @@ bool UI_panel_category_is_visible(const ARegion *region) PanelCategoryDyn *UI_panel_category_find(const ARegion *region, const char *idname) { - return BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname)); + return static_cast<PanelCategoryDyn *>( + BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname))); } PanelCategoryStack *UI_panel_category_active_find(ARegion *region, const char *idname) { - return BLI_findstring( - ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); + return static_cast<PanelCategoryStack *>(BLI_findstring( + ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname))); } static void ui_panel_category_active_set(ARegion *region, const char *idname, bool fallback) @@ -2175,7 +2153,7 @@ static void ui_panel_category_active_set(ARegion *region, const char *idname, bo BLI_remlink(lb, pc_act); } else { - pc_act = MEM_callocN(sizeof(PanelCategoryStack), __func__); + pc_act = MEM_cnew<PanelCategoryStack>(__func__); BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); } @@ -2226,14 +2204,14 @@ const char *UI_panel_category_active_get(ARegion *region, bool set_fallback) } if (set_fallback) { - PanelCategoryDyn *pc_dyn = region->panels_category.first; + PanelCategoryDyn *pc_dyn = static_cast<PanelCategoryDyn *>(region->panels_category.first); if (pc_dyn) { ui_panel_category_active_set(region, pc_dyn->idname, true); return pc_dyn->idname; } } - return NULL; + return nullptr; } static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event) @@ -2244,12 +2222,12 @@ static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const } } - return NULL; + return nullptr; } void UI_panel_category_add(ARegion *region, const char *name) { - PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__); + PanelCategoryDyn *pc_dyn = MEM_cnew<PanelCategoryDyn>(__func__); BLI_addtail(®ion->panels_category, pc_dyn); BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname)); @@ -2294,7 +2272,8 @@ static int ui_handle_panel_category_cycling(const wmEvent *event, pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next; if (!pc_dyn) { /* Proper cyclic behavior, back to first/last category (only used for ctrl+tab). */ - pc_dyn = backwards ? region->panels_category.last : region->panels_category.first; + pc_dyn = backwards ? static_cast<PanelCategoryDyn *>(region->panels_category.last) : + static_cast<PanelCategoryDyn *>(region->panels_category.first); } } @@ -2359,11 +2338,11 @@ int ui_handler_panel_region(bContext *C, return retval; } - const bool region_has_active_button = (ui_region_find_active_but(region) != NULL); + const bool region_has_active_button = (ui_region_find_active_but(region) != nullptr); LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { Panel *panel = block->panel; - if (panel == NULL || panel->type == NULL) { + if (panel == nullptr || panel->type == nullptr) { continue; } /* We can't expand or collapse panels without headers, they would disappear. */ @@ -2434,10 +2413,10 @@ void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *pt void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) { - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ - if (panel->runtime.custom_data_ptr != NULL) { + if (panel->runtime.custom_data_ptr != nullptr) { MEM_freeN(panel->runtime.custom_data_ptr); } @@ -2455,7 +2434,7 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { Panel *panel = block->panel; - if (panel == NULL) { + if (panel == nullptr) { continue; } @@ -2468,12 +2447,12 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm } } - return NULL; + return nullptr; } bool UI_panel_can_be_pinned(const Panel *panel) { - return (panel->type->parent == NULL) && !(panel->type->flag & PANEL_TYPE_INSTANCED); + return (panel->type->parent == nullptr) && !(panel->type->flag & PANEL_TYPE_INSTANCED); } /** \} */ @@ -2485,8 +2464,8 @@ bool UI_panel_can_be_pinned(const Panel *panel) /* NOTE: this is modal handler and should not swallow events for animation. */ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) { - Panel *panel = userdata; - uiHandlePanelData *data = panel->activedata; + Panel *panel = static_cast<Panel *>(userdata); + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); /* Verify if we can stop. */ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { @@ -2506,7 +2485,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) } } - data = panel->activedata; + data = static_cast<uiHandlePanelData *>(panel->activedata); if (data && data->state == PANEL_STATE_ANIMATION) { return WM_UI_HANDLER_CONTINUE; @@ -2516,7 +2495,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) static void ui_handler_remove_panel(bContext *C, void *userdata) { - Panel *panel = userdata; + Panel *panel = static_cast<Panel *>(userdata); panel_activate_state(C, panel, PANEL_STATE_EXIT); } @@ -2527,13 +2506,13 @@ static void panel_handle_data_ensure(const bContext *C, Panel *panel, const uiHandlePanelState state) { - if (panel->activedata == NULL) { + if (panel->activedata == nullptr) { panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__); WM_event_add_ui_handler( C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0); } - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL); @@ -2554,11 +2533,11 @@ static void panel_handle_data_ensure(const bContext *C, */ static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); wmWindow *win = CTX_wm_window(C); ARegion *region = CTX_wm_region(C); - if (data != NULL && data->state == state) { + if (data != nullptr && data->state == state) { return; } @@ -2582,15 +2561,15 @@ static void panel_activate_state(const bContext *C, Panel *panel, const uiHandle else if (state == PANEL_STATE_EXIT) { panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, false); - BLI_assert(data != NULL); + BLI_assert(data != nullptr); if (data->animtimer) { WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer); - data->animtimer = NULL; + data->animtimer = nullptr; } MEM_freeN(data); - panel->activedata = NULL; + panel->activedata = nullptr; WM_event_remove_ui_handler( &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false); diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc index 8572e938b30..becdfaf4e25 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.cc +++ b/source/blender/editors/interface/interface_region_menu_pie.cc @@ -37,7 +37,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Pie Menu diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index a22f7218203..0647e1a4a70 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -39,7 +39,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Utility Functions diff --git a/source/blender/editors/interface/interface_region_popover.cc b/source/blender/editors/interface/interface_region_popover.cc index 2e10261a4f7..c152a9aacd5 100644 --- a/source/blender/editors/interface/interface_region_popover.cc +++ b/source/blender/editors/interface/interface_region_popover.cc @@ -46,7 +46,7 @@ #include "UI_interface.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Popup Menu with Callback or String diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc index 74c228e3338..f6b078c033e 100644 --- a/source/blender/editors/interface/interface_region_popup.cc +++ b/source/blender/editors/interface/interface_region_popup.cc @@ -31,7 +31,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Utility Functions diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index 81c0c29d09a..6bb47666afd 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -41,7 +41,7 @@ #include "GPU_state.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" #define MENU_BORDER (int)(0.3f * U.widget_unit) @@ -710,18 +710,18 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, type.regionid = RGN_TYPE_TEMPORARY; region->type = &type; - /* create searchbox data */ + /* Create search-box data. */ uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__); - /* set font, get bb */ + /* Set font, get the bounding-box. */ data->fstyle = style->widget; /* copy struct */ ui_fontscale(&data->fstyle.points, aspect); UI_fontstyle_set(&data->fstyle); region->regiondata = data; - /* special case, hardcoded feature, not draw backdrop when called from menus, - * assume for design that popup already added it */ + /* Special case, hard-coded feature, not draw backdrop when called from menus, + * assume for design that popup already added it. */ if (but->block->flag & UI_BLOCK_SEARCH_MENU) { data->noback = true; } diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.cc index f460a159a5f..6a39b761983 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.cc @@ -16,9 +16,9 @@ * For now it's not a priority, so leave as-is. */ -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> +#include <cstdarg> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -53,7 +53,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" #define UI_TIP_PAD_FAC 1.3f #define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) @@ -61,59 +61,82 @@ #define UI_TIP_STR_MAX 1024 -typedef struct uiTooltipFormat { - enum { - UI_TIP_STYLE_NORMAL = 0, - UI_TIP_STYLE_HEADER, - UI_TIP_STYLE_MONO, - } style : 3; - enum { - UI_TIP_LC_MAIN = 0, /* primary text */ - UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */ - UI_TIP_LC_ACTIVE, /* titles of active enum values */ - UI_TIP_LC_NORMAL, /* regular text */ - UI_TIP_LC_PYTHON, /* Python snippet */ - UI_TIP_LC_ALERT, /* description of why operator can't run */ - } color_id : 4; - int is_pad : 1; -} uiTooltipFormat; - -typedef struct uiTooltipField { +struct uiTooltipFormat { + enum class Style : int8_t { + Normal, + Header, + Mono, + }; + enum class ColorID : int8_t { + /** Primary Text. */ + Main = 0, + /** The value of buttons (also shortcuts). */ + Value = 1, + /** Titles of active enum values. */ + Active = 2, + /** Regular text. */ + Normal = 3, + /** Python snippet. */ + Python = 4, + /** Description of why an operator can't run. */ + Alert = 5, + }; + Style style; + ColorID color_id; + bool is_pad; +}; + +struct uiTooltipField { char *text; char *text_suffix; struct { - uint x_pos; /* x cursor position at the end of the last line */ - uint lines; /* number of lines, 1 or more with word-wrap */ + /** X cursor position at the end of the last line. */ + uint x_pos; + /** Number of lines, 1 or more with word-wrap. */ + uint lines; } geom; uiTooltipFormat format; +}; -} uiTooltipField; - -typedef struct uiTooltipData { +struct uiTooltipData { rcti bbox; uiTooltipField *fields; uint fields_len; uiFontStyle fstyle; int wrap_width; int toth, lineh; -} uiTooltipData; +}; #define UI_TIP_LC_MAX 6 -BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max"); +BLI_STATIC_ASSERT(UI_TIP_LC_MAX == static_cast<int>(uiTooltipFormat::ColorID::Alert) + 1, + "invalid lc-max"); BLI_STATIC_ASSERT(sizeof(uiTooltipFormat) <= sizeof(int), "oversize"); static uiTooltipField *text_field_add_only(uiTooltipData *data) { data->fields_len += 1; - data->fields = MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len); + data->fields = static_cast<uiTooltipField *>( + MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len)); return &data->fields[data->fields_len - 1]; } -static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format) +// static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format) +// { +// uiTooltipField *field = text_field_add_only(data); +// field->format = *format; +// return field; +// } + +static uiTooltipField *text_field_add(uiTooltipData *data, + const uiTooltipFormat::Style style, + const uiTooltipFormat::ColorID color, + const bool is_pad = false) { uiTooltipField *field = text_field_add_only(data); - field->format = *format; + field->format = {}; + field->format.style = style; + field->format.color_id = color, field->format.is_pad = is_pad; return field; } @@ -138,30 +161,31 @@ static void rgb_tint(float col[3], float h, float h_strength, float v, float v_s static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region) { const float pad_px = UI_TIP_PADDING; - uiTooltipData *data = region->regiondata; + uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata); const uiWidgetColors *theme = ui_tooltip_get_theme(); rcti bbox = data->bbox; float tip_colors[UI_TIP_LC_MAX][3]; uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */ - float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */ - float *value_color = tip_colors[UI_TIP_LC_VALUE]; - float *active_color = tip_colors[UI_TIP_LC_ACTIVE]; - float *normal_color = tip_colors[UI_TIP_LC_NORMAL]; - float *python_color = tip_colors[UI_TIP_LC_PYTHON]; - float *alert_color = tip_colors[UI_TIP_LC_ALERT]; + /* The color from the theme. */ + float *main_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)]; + float *value_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Value)]; + float *active_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)]; + float *normal_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Normal)]; + float *python_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Python)]; + float *alert_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Alert)]; float background_color[3]; wmOrtho2_region_pixelspace(region); - /* draw background */ - ui_draw_tooltip_background(UI_style_get(), NULL, &bbox); + /* Draw background. */ + ui_draw_tooltip_background(UI_style_get(), nullptr, &bbox); /* set background_color */ rgb_uchar_to_float(background_color, theme->inner); - /* calculate normal_color */ + /* Calculate `normal_color`. */ rgb_uchar_to_float(main_color, theme->text); copy_v3_v3(active_color, main_color); copy_v3_v3(normal_color, main_color); @@ -169,19 +193,19 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region copy_v3_v3(alert_color, main_color); copy_v3_v3(value_color, main_color); - /* find the brightness difference between background and text colors */ + /* Find the brightness difference between background and text colors. */ const float tone_bg = rgb_to_grayscale(background_color); - /* tone_fg = rgb_to_grayscale(main_color); */ + // tone_fg = rgb_to_grayscale(main_color); - /* mix the colors */ + /* Mix the colors. */ rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* Light gray. */ rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* Light blue. */ rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* Gray. */ rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* Dark gray. */ rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* Red. */ - /* draw text */ + /* Draw text. */ BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); BLF_wordwrap(blf_mono_font, data->wrap_width); @@ -190,58 +214,58 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region for (int i = 0; i < data->fields_len; i++) { const uiTooltipField *field = &data->fields[i]; - const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : + nullptr; bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines); - if (field->format.style == UI_TIP_STYLE_HEADER) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; - /* draw header and active data (is done here to be able to change color) */ - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); + if (field->format.style == uiTooltipFormat::Style::Header) { + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; + + /* Draw header and active data (is done here to be able to change color). */ + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)]); UI_fontstyle_set(&data->fstyle); UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); - /* offset to the end of the last line */ + /* Offset to the end of the last line. */ if (field->text_suffix) { const float xofs = field->geom.x_pos; const float yofs = data->lineh * (field->geom.lines - 1); bbox.xmin += xofs; bbox.ymax -= yofs; - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); + rgb_float_to_uchar(drawcol, + tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)]); UI_fontstyle_draw( &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params); - /* undo offset */ + /* Undo offset. */ bbox.xmin -= xofs; bbox.ymax += yofs; } } - else if (field->format.style == UI_TIP_STYLE_MONO) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; + else if (field->format.style == uiTooltipFormat::Style::Mono) { + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; uiFontStyle fstyle_mono = data->fstyle; fstyle_mono.uifont_id = blf_mono_font; UI_fontstyle_set(&fstyle_mono); - /* XXX, needed because we don't have mono in 'U.uifonts' */ + /* XXX: needed because we don't have mono in 'U.uifonts'. */ BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]); UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } else { - BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL); - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; - - /* draw remaining data */ - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + BLI_assert(field->format.style == uiTooltipFormat::Style::Normal); + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; + + /* Draw remaining data. */ + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]); UI_fontstyle_set(&data->fstyle); UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } @@ -259,7 +283,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region static void ui_tooltip_region_free_cb(ARegion *region) { - uiTooltipData *data = region->regiondata; + uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata); for (int i = 0; i < data->fields_len; i++) { const uiTooltipField *field = &data->fields[i]; @@ -270,7 +294,7 @@ static void ui_tooltip_region_free_cb(ARegion *region) } MEM_freeN(data->fields); MEM_freeN(data); - region->regiondata = NULL; + region->regiondata = nullptr; } /** \} */ @@ -281,7 +305,7 @@ static void ui_tooltip_region_free_cb(ARegion *region) static char *ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr) { - char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, opptr); + char *str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr); /* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */ WM_operator_pystring_abbreviate(str, 32); @@ -304,24 +328,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); - if (ot != NULL) { - /* Tip */ + if (ot != nullptr) { + /* Tip. */ { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = BLI_strdup(ot->description ? ot->description : ot->name); } - /* Shortcut */ + /* Shortcut. */ { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); bool found = false; if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) { found = true; @@ -329,13 +346,10 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); } - /* Python */ + /* Python. */ if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_PYTHON, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python); char *str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr); field->text = BLI_sprintfN(TIP_("Python: %s"), str); MEM_freeN(str); @@ -353,17 +367,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, */ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label) { - if (but->optype == NULL) { - return NULL; + if (but->optype == nullptr) { + return nullptr; } if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) { - return NULL; + return nullptr; } /* Needed to get the space-data's type (below). */ - if (CTX_wm_space_data(C) == NULL) { - return NULL; + if (CTX_wm_space_data(C) == nullptr) { + return nullptr; } char tool_id[MAX_NAME]; @@ -378,7 +392,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is const char *has_valid_context_error = IFACE_("Unsupported context"); { ScrArea *area = CTX_wm_area(C); - if (area == NULL) { + if (area == nullptr) { has_valid_context = false; } else { @@ -393,16 +407,15 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } /* We have a tool, now extract the info. */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); #ifdef WITH_PYTHON - /* it turns out to be most simple to do this via Python since C - * doesn't have access to information about non-active tools. - */ + /* It turns out to be most simple to do this via Python since C + * doesn't have access to information about non-active tools. */ /* Title (when icon-only). */ if (but->drawstr[0] == '\0') { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "bl_ui.space_toolsystem_common.item_from_id(" @@ -410,16 +423,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is "bpy.context.space_data.type, " "'%s').label", tool_id); - char *expr_result = NULL; + char *expr_result = nullptr; bool is_error = false; if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) { if (STREQ(expr_result, "")) { MEM_freeN(expr_result); - expr_result = NULL; + expr_result = nullptr; } } else { @@ -429,7 +442,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is is_error = true; } - if (expr_result != NULL) { + if (expr_result != nullptr) { /* NOTE: This is a very weak hack to get a valid translation most of the time... * Proper way to do would be to get i18n context from the item, somehow. */ const char *label_str = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, expr_result); @@ -442,23 +455,19 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is expr_result = BLI_strdup(label_str); } - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = expr_result; if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; + field->format.color_id = uiTooltipFormat::ColorID::Alert; } } } /* Tip. */ if (is_label == false) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "bl_ui.space_toolsystem_common.description_from_id(" @@ -467,16 +476,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is "'%s') + '.'", tool_id); - char *expr_result = NULL; + char *expr_result = nullptr; bool is_error = false; if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) { if (STREQ(expr_result, ".")) { MEM_freeN(expr_result); - expr_result = NULL; + expr_result = nullptr; } } else { @@ -486,17 +495,13 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is is_error = true; } - if (expr_result != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + if (expr_result != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = expr_result; if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; + field->format.color_id = uiTooltipFormat::ColorID::Alert; } } } @@ -515,18 +520,18 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is * * Either way case it's useful to show the shortcut. */ - char *shortcut = NULL; + char *shortcut = nullptr; { - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - UI_but_string_info_get(C, but, &op_keymap, NULL); + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr}; + UI_but_string_info_get(C, but, &op_keymap, nullptr); shortcut = op_keymap.strinfo; } - if (shortcut == NULL) { + if (shortcut == nullptr) { const ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - if (tool_attr != NULL) { + if (tool_attr != nullptr) { const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); const char *tool_id_lstrip = strrchr(tool_id, '.'); const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0; @@ -543,7 +548,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (WM_key_event_operator_string(C, ot->idname, WM_OP_INVOKE_REGION_WIN, - op_props.data, + static_cast<IDProperty *>(op_props.data), true, shortcut_brush, ARRAY_SIZE(shortcut_brush))) { @@ -554,20 +559,20 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } } - if (shortcut == NULL) { + if (shortcut == nullptr) { /* Check for direct access to the tool. */ char shortcut_toolbar[128] = ""; if (WM_key_event_operator_string(C, "WM_OT_toolbar", WM_OP_INVOKE_REGION_WIN, - NULL, + nullptr, true, shortcut_toolbar, ARRAY_SIZE(shortcut_toolbar))) { /* Generate keymap in order to inspect it. * NOTE: we could make a utility to avoid the keymap generation part of this. */ const char *expr_imports[] = { - "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL}; + "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", nullptr}; const char *expr = ("getattr(" "bl_keymap_utils.keymap_from_toolbar.generate(" @@ -580,7 +585,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { shortcut = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) { if (expr_result != 0) { wmKeyMap *keymap = (wmKeyMap *)expr_result; LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { @@ -603,13 +608,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } } - if (shortcut != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + if (shortcut != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut); MEM_freeN(shortcut); } @@ -627,11 +628,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is * This is a little involved since the shortcut may be bound to another tool in this group, * instead of the current tool on display. */ - char *expr_result = NULL; + char *expr_result = nullptr; size_t expr_result_len; { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "'\\x00'.join(" @@ -645,12 +646,12 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* pass */ } else if (BPY_run_string_as_string_and_size( - C, expr_imports, expr, NULL, &expr_result, &expr_result_len)) { + C, expr_imports, expr, nullptr, &expr_result, &expr_result_len)) { /* pass. */ } } - if (expr_result != NULL) { + if (expr_result != nullptr) { PointerRNA op_props; WM_operator_properties_create_ptr(&op_props, but->optype); RNA_boolean_set(&op_props, "cycle", true); @@ -665,7 +666,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (WM_key_event_operator_string(C, but->optype->idname, WM_OP_INVOKE_REGION_WIN, - op_props.data, + static_cast<IDProperty *>(op_props.data), true, shortcut, ARRAY_SIZE(shortcut))) { @@ -678,12 +679,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is MEM_freeN(expr_result); if (shortcut[0] != '\0') { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut Cycle: %s"), shortcut); } } @@ -691,12 +688,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* Python */ if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python, true); char *str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr); field->text = BLI_sprintfN(TIP_("Python: %s"), str); MEM_freeN(str); @@ -706,7 +699,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* This is too handy not to expose somehow, let's be sneaky for now. */ if ((is_label == false) && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "getattr(" @@ -722,15 +715,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { /* pass */ } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) { if (expr_result != 0) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup("Tool Keymap:"); } wmKeyMap *keymap = (wmKeyMap *)expr_result; @@ -747,7 +736,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -756,26 +745,26 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon) { - uiStringInfo but_label = {BUT_GET_LABEL, NULL}; - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; + uiStringInfo but_label = {BUT_GET_LABEL, nullptr}; + uiStringInfo but_tip = {BUT_GET_TIP, nullptr}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr}; + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr}; + uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, nullptr}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr}; char buf[512]; wmOperatorType *optype = extra_icon ? UI_but_extra_operator_icon_optype_get(extra_icon) : but->optype; - PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop; + PropertyRNA *rnaprop = extra_icon ? nullptr : but->rnaprop; /* create tooltip data */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); if (extra_icon) { - UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, NULL); + UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, nullptr); } else { UI_but_string_info_get(C, @@ -788,30 +777,25 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, &prop_keymap, &rna_struct, &rna_prop, - NULL); + nullptr); } /* Tip Label (only for buttons not already showing the label). * Check prefix instead of comparing because the button may include the shortcut. - * Buttons with dynamic tooltips also don't get their default label here since they - * can already provide more accurate and specific tooltip content. */ + * Buttons with dynamic tool-tips also don't get their default label here since they + * can already provide more accurate and specific tool-tip content. */ if (but_label.strinfo && !STRPREFIX(but->drawstr, but_label.strinfo) && !but->tip_func) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal); + field->text = BLI_strdup(but_label.strinfo); } /* Tip */ if (but_tip.strinfo) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal); if (enum_label.strinfo) { field->text = BLI_sprintfN("%s: ", but_tip.strinfo); field->text_suffix = BLI_strdup(enum_label.strinfo); @@ -823,59 +807,40 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* special case enum rna buttons */ if ((but->type & UI_BTYPE_ROW) && rnaprop && RNA_property_flag(rnaprop) & PROP_ENUM_FLAG) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_strdup(TIP_("(Shift-Click/Drag to select multiple)")); } } - /* Enum field label & tip */ + /* Enum field label & tip. */ if (enum_tip.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value); field->text = BLI_strdup(enum_tip.strinfo); } - /* Op shortcut */ + /* Operator shortcut. */ if (op_keymap.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), op_keymap.strinfo); } - /* Property context-toggle shortcut */ + /* Property context-toggle shortcut. */ if (prop_keymap.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), prop_keymap.strinfo); } if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { - /* better not show the value of a password */ + /* Better not show the value of a password. */ if ((rnaprop && (RNA_property_subtype(rnaprop) == PROP_PASSWORD)) == 0) { - /* full string */ + /* Full string. */ ui_but_string_get(but, buf, sizeof(buf)); if (buf[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Value: %s"), buf); } } @@ -890,22 +855,16 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, RNA_property_float_get_index(&but->rnapoin, rnaprop, but->rnaindex) : RNA_property_float_get(&but->rnapoin, rnaprop); - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value); field->text = BLI_sprintfN(TIP_("Radians: %f"), value); } } if (but->flag & UI_BUT_DRIVEN) { if (ui_but_anim_expression_get(but, buf, sizeof(buf))) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_sprintfN(TIP_("Expression: %s"), buf); } } @@ -913,64 +872,56 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if (but->rnapoin.owner_id) { const ID *id = but->rnapoin.owner_id; if (ID_IS_LINKED(id)) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->filepath); } } } else if (optype) { PointerRNA *opptr = extra_icon ? UI_but_extra_operator_icon_opptr_get(extra_icon) : - /* allocated when needed, the button owns it */ + /* Allocated when needed, the button owns it. */ UI_but_operator_ptr_get(but); - /* so the context is passed to fieldf functions (some py fieldf functions use it) */ + /* So the context is passed to field functions (some Python field functions use it). */ WM_operator_properties_sanitize(opptr, false); char *str = ui_tooltip_text_python_from_op(C, optype, opptr); - /* operator info */ + /* Operator info. */ if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true); field->text = BLI_sprintfN(TIP_("Python: %s"), str); } MEM_freeN(str); } - /* button is disabled, we may be able to tell user why */ + /* Button is disabled, we may be able to tell user why. */ if ((but->flag & UI_BUT_DISABLED) || extra_icon) { - const char *disabled_msg = NULL; + const char *disabled_msg = nullptr; bool disabled_msg_free = false; - /* if operator poll check failed, it can give pretty precise info why */ + /* If operator poll check failed, it can give pretty precise info why. */ if (optype) { const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext : but->opcontext; + wmOperatorCallParams call_params{}; + call_params.optype = optype; + call_params.opcontext = opcontext; CTX_wm_operator_poll_msg_clear(C); - ui_but_context_poll_operator_ex( - C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext}); + ui_but_context_poll_operator_ex(C, but, &call_params); disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free); } - /* alternatively, buttons can store some reasoning too */ + /* Alternatively, buttons can store some reasoning too. */ else if (!extra_icon && but->disabled_info) { disabled_msg = TIP_(but->disabled_info); } if (disabled_msg && disabled_msg[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_ALERT, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Alert); field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg); } if (disabled_msg_free) { @@ -980,30 +931,23 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if ((U.flag & USER_TOOLTIPS_PYTHON) && !optype && rna_struct.strinfo) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true); if (rna_prop.strinfo) { /* Struct and prop */ field->text = BLI_sprintfN(TIP_("Python: %s.%s"), rna_struct.strinfo, rna_prop.strinfo); } else { - /* Only struct (e.g. menus) */ + /* Only struct (e.g. menus). */ field->text = BLI_sprintfN(TIP_("Python: %s"), rna_struct.strinfo); } } if (but->rnapoin.owner_id) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python); - /* this could get its own 'BUT_GET_...' type */ + /* This could get its own `BUT_GET_...` type. */ /* never fails */ /* Move ownership (no need for re-allocation). */ @@ -1045,73 +989,66 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) { - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); - /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */ + /* TODO(@campbellbarton): a way for gizmos to have their own descriptions (low priority). */ /* Operator Actions */ { const bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part; - const struct { + struct GizmoOpActions { int part; const char *prefix; - } gzop_actions[] = { + }; + GizmoOpActions gzop_actions[] = { { - .part = gz->highlight_part, - .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : NULL, + gz->highlight_part, + use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : nullptr, }, { - .part = use_drag ? gz->drag_part : -1, - .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : NULL, + use_drag ? gz->drag_part : -1, + use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : nullptr, }, }; for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) { wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ? WM_gizmo_operator_get(gz, gzop_actions[i].part) : - NULL; - if (gzop != NULL) { + nullptr; + if (gzop != nullptr) { /* Description */ char *info = WM_operatortype_description_or_name(C, gzop->type, &gzop->ptr); - if (info != NULL) { + if (info != nullptr) { char *text = info; - if (gzop_actions[i].prefix != NULL) { + if (gzop_actions[i].prefix != nullptr) { text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info); MEM_freeN(info); } - if (text != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + if (text != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Value, true); field->text = text; } } /* Shortcut */ { - IDProperty *prop = gzop->ptr.data; + IDProperty *prop = static_cast<IDProperty *>(gzop->ptr.data); char buf[128]; if (WM_key_event_operator_string( C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, buf, ARRAY_SIZE(buf))) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf); } } @@ -1123,17 +1060,13 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) if (gz->type->target_property_defs_len) { wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz); for (int i = 0; i < gz->type->target_property_defs_len; i++) { - /* TODO(campbell): function callback descriptions. */ + /* TODO(@campbellbarton): function callback descriptions. */ wmGizmoProperty *gz_prop = &gz_prop_array[i]; - if (gz_prop->prop != NULL) { + if (gz_prop->prop != nullptr) { const char *info = RNA_property_ui_description(gz_prop->prop); if (info && info[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_strdup(info); } } @@ -1142,7 +1075,7 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -1161,7 +1094,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, rcti rect_i; int font_flag = 0; - /* create area region */ + /* Create area region. */ ARegion *region = ui_region_temp_add(CTX_wm_screen(C)); static ARegionType type; @@ -1171,7 +1104,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, type.regionid = RGN_TYPE_TEMPORARY; region->type = &type; - /* set font, get bb */ + /* Set font, get bounding-box. */ data->fstyle = style->widget; /* copy struct */ ui_fontscale(&data->fstyle.points, aspect); @@ -1185,7 +1118,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); BLF_wordwrap(blf_mono_font, data->wrap_width); - /* these defines tweaked depending on font */ + /* These defines tweaked depending on font. */ #define TIP_BORDER_X (16.0f / aspect) #define TIP_BORDER_Y (6.0f / aspect) @@ -1194,18 +1127,19 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, int i, fonth, fontw; for (i = 0, fontw = 0, fonth = 0; i < data->fields_len; i++) { uiTooltipField *field = &data->fields[i]; - uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : nullptr; struct ResultBLF info; int w, x_pos = 0; int font_id; - if (field->format.style == UI_TIP_STYLE_MONO) { + if (field->format.style == uiTooltipFormat::Style::Mono) { BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi); font_id = blf_mono_font; } else { - BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER)); + BLI_assert(ELEM( + field->format.style, uiTooltipFormat::Style::Normal, uiTooltipFormat::Style::Header)); font_id = data->fstyle.uifont_id; } w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info); @@ -1253,22 +1187,20 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, /* Clamp to window bounds. */ { - /* Ensure at least 5 px above screen bounds - * UI_UNIT_Y is just a guess to be above the menu item */ - if (init_rect_overlap != NULL) { + /* Ensure at least 5 px above screen bounds. + * #UI_UNIT_Y is just a guess to be above the menu item. */ + if (init_rect_overlap != nullptr) { const int pad = max_ff(1.0f, U.pixelsize) * 5; - const rcti init_rect = { - .xmin = init_rect_overlap->xmin - pad, - .xmax = init_rect_overlap->xmax + pad, - .ymin = init_rect_overlap->ymin - pad, - .ymax = init_rect_overlap->ymax + pad, - }; - const rcti rect_clamp = { - .xmin = 0, - .xmax = winx, - .ymin = 0, - .ymax = winy, - }; + rcti init_rect; + init_rect.xmin = init_rect_overlap->xmin - pad; + init_rect.xmax = init_rect_overlap->xmax + pad; + init_rect.ymin = init_rect_overlap->ymin - pad; + init_rect.ymax = init_rect_overlap->ymax + pad; + rcti rect_clamp; + rect_clamp.xmin = 0; + rect_clamp.xmax = winx; + rect_clamp.ymin = 0; + rect_clamp.ymax = winy; /* try right. */ const int size_x = BLI_rcti_size_x(&rect_i); const int size_y = BLI_rcti_size_y(&rect_i); @@ -1348,12 +1280,11 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, } else { const int pad = max_ff(1.0f, U.pixelsize) * 5; - const rcti rect_clamp = { - .xmin = pad, - .xmax = winx - pad, - .ymin = pad + (UI_UNIT_Y * 2), - .ymax = winy - pad, - }; + rcti rect_clamp; + rect_clamp.xmin = pad; + rect_clamp.xmax = winx - pad; + rect_clamp.ymin = pad + (UI_UNIT_Y * 2); + rect_clamp.ymax = winy - pad; int offset_dummy[2]; BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy); } @@ -1368,7 +1299,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, { /* Compensate for margin offset, visually this corrects the position. */ const int margin = UI_POPUP_MARGIN; - if (init_rect_overlap != NULL) { + if (init_rect_overlap != nullptr) { BLI_rcti_translate(&rect_i, margin, margin / 2); } @@ -1403,29 +1334,29 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon( bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label) { wmWindow *win = CTX_wm_window(C); - /* aspect values that shrink text are likely unreadable */ + /* Aspect values that shrink text are likely unreadable. */ const float aspect = min_ff(1.0f, but->block->aspect); float init_position[2]; if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; + return nullptr; } - uiTooltipData *data = NULL; + uiTooltipData *data = nullptr; - if (data == NULL) { + if (data == nullptr) { data = ui_tooltip_data_from_tool(C, but, is_label); } - if (data == NULL) { + if (data == nullptr) { data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon); } - if (data == NULL) { - data = ui_tooltip_data_from_button_or_extra_icon(C, but, NULL); + if (data == nullptr) { + data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr); } - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(but); @@ -1454,31 +1385,30 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon( } ARegion *region = ui_tooltip_create_with_data( - C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect); + C, data, init_position, is_no_overlap ? &init_rect : nullptr, aspect); return region; } ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) { - return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label); + return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, nullptr, is_label); } ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) { wmWindow *win = CTX_wm_window(C); const float aspect = 1.0f; - float init_position[2] = {win->eventstate->xy[0], win->eventstate->xy[1]}; + float init_position[2] = {static_cast<float>(win->eventstate->xy[0]), + static_cast<float>(win->eventstate->xy[1])}; uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz); - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } - /* TODO(harley): - * Julian preferred that the gizmo callback return the 3D bounding box - * which we then project to 2D here. Would make a nice improvement. - */ + /* TODO(@harley): Julian preferred that the gizmo callback return the 3D bounding box + * which we then project to 2D here. Would make a nice improvement. */ if (gz->type->screen_bounds_get) { rcti bounds; if (gz->type->screen_bounds_get(C, gz, &bounds)) { @@ -1487,46 +1417,34 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) } } - return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); + return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect); } static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data( const uiSearchItemTooltipData *item_tooltip_data) { - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); if (item_tooltip_data->description[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup(item_tooltip_data->description); } if (item_tooltip_data->name && item_tooltip_data->name[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_strdup(item_tooltip_data->name); } if (item_tooltip_data->hint[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup(item_tooltip_data->hint); } if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -1538,8 +1456,8 @@ ARegion *UI_tooltip_create_from_search_item_generic( const uiSearchItemTooltipData *item_tooltip_data) { uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data); - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } const float aspect = 1.0f; @@ -1548,7 +1466,7 @@ ARegion *UI_tooltip_create_from_search_item_generic( init_position[0] = win->eventstate->xy[0]; init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2); - return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); + return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect); } void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region) diff --git a/source/blender/editors/interface/interface_regions.cc b/source/blender/editors/interface/interface_regions.cc index 1a2c1f7919c..1770805cf59 100644 --- a/source/blender/editors/interface/interface_regions.cc +++ b/source/blender/editors/interface/interface_regions.cc @@ -21,7 +21,7 @@ #include "ED_screen.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" ARegion *ui_region_temp_add(bScreen *screen) { diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.hh index 2ed2cb3d68b..6287a031f5c 100644 --- a/source/blender/editors/interface/interface_regions_intern.h +++ b/source/blender/editors/interface/interface_regions_intern.hh @@ -3,23 +3,16 @@ /** \file * \ingroup edinterface * - * Share between interface_region_*.c files. + * Share between interface_region_*.cc files. */ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - -/* interface_region_menu_popup.c */ +/* interface_region_menu_popup.cc */ uint ui_popup_menu_hash(const char *str); -/* interface_regions_intern.h */ +/* interface_regions.cc */ + ARegion *ui_region_temp_add(bScreen *screen); void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 8588c7cabc0..3147deb5ad1 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -66,7 +66,7 @@ static void asset_view_item_but_drag_set(uiBut *but, } static void asset_view_draw_item(uiList *ui_list, - bContext *UNUSED(C), + const bContext *UNUSED(C), uiLayout *layout, PointerRNA *UNUSED(dataptr), PointerRNA *itemptr, @@ -183,7 +183,7 @@ static void asset_view_template_refresh_asset_collection( } void uiTemplateAssetView(uiLayout *layout, - bContext *C, + const bContext *C, const char *list_id, PointerRNA *asset_library_dataptr, const char *asset_library_propname, diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index e0b6bbb34c4..f0c91588f98 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -83,7 +83,7 @@ struct TemplateListVisualInfo { }; static void uilist_draw_item_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, @@ -114,7 +114,7 @@ static void uilist_draw_item_default(struct uiList *ui_list, } static void uilist_draw_filter_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout) { PointerRNA listptr; @@ -160,7 +160,7 @@ static int cmpstringp(const void *p1, const void *p2) } static void uilist_filter_items_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct PointerRNA *dataptr, const char *propname) { @@ -434,7 +434,7 @@ static void ui_template_list_collect_items(PointerRNA *list_ptr, /** * Create the UI-list representation of the list items, sorted and filtered if needed. */ -static void ui_template_list_collect_display_items(bContext *C, +static void ui_template_list_collect_display_items(const bContext *C, uiList *ui_list, TemplateListInputData *input_data, const uiListFilterItemsFunc filter_items_fn, @@ -601,7 +601,7 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha /** * \note that \a layout_type may be null. */ -static uiList *ui_list_ensure(bContext *C, +static uiList *ui_list_ensure(const bContext *C, uiListType *ui_list_type, const char *list_id, int layout_type, @@ -656,7 +656,7 @@ static uiList *ui_list_ensure(bContext *C, return ui_list; } -static void ui_template_list_layout_draw(bContext *C, +static void ui_template_list_layout_draw(const bContext *C, uiList *ui_list, uiLayout *layout, TemplateListInputData *input_data, @@ -1156,7 +1156,7 @@ static void ui_template_list_layout_draw(bContext *C, } uiList *uiTemplateList_ex(uiLayout *layout, - bContext *C, + const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, @@ -1227,7 +1227,7 @@ uiList *uiTemplateList_ex(uiLayout *layout, } void uiTemplateList(uiLayout *layout, - bContext *C, + const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.cc index 41de2ab197d..0d0a5f01744 100644 --- a/source/blender/editors/interface/interface_template_search_operator.c +++ b/source/blender/editors/interface/interface_template_search_operator.cc @@ -7,14 +7,15 @@ * accessed via the #WM_OT_search_operator operator. */ -#include <string.h> +#include <cstring> #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_ghash.h" +#include "BLI_math_vec_types.hh" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -35,10 +36,10 @@ static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { - wmOperatorType *ot = arg2; + wmOperatorType *ot = static_cast<wmOperatorType *>(arg2); if (ot) { - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } } @@ -53,19 +54,20 @@ static void operator_search_update_fn(const bContext *C, /* Prepare BLI_string_all_words_matched. */ const size_t str_len = strlen(str); const int words_max = BLI_string_max_possible_word_count(str_len); - int(*words)[2] = BLI_array_alloca(words, words_max); - const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); + blender::Array<blender::int2> words(words_max); + const int words_len = BLI_string_find_split_words( + str, str_len, ' ', (int(*)[2])words.data(), words_max); for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + wmOperatorType *ot = static_cast<wmOperatorType *>(BLI_ghashIterator_getValue(&iter)); const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { continue; } - if (BLI_string_all_words_matched(ot_ui_name, str, words, words_len)) { + if (BLI_string_all_words_matched(ot_ui_name, str, (int(*)[2])words.data(), words_len)) { if (WM_operator_poll((bContext *)C, ot)) { char name[256]; const int len = strlen(ot_ui_name); @@ -78,7 +80,7 @@ static void operator_search_update_fn(const bContext *C, if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, - NULL, + nullptr, true, &name[len + 1], sizeof(name) - len - 1)) { @@ -105,11 +107,11 @@ void UI_but_func_operator_search(uiBut *but) UI_but_func_search_set(but, ui_searchbox_create_operator, operator_search_update_fn, - NULL, + nullptr, false, - NULL, + nullptr, operator_search_exec_fn, - NULL); + nullptr); } void uiTemplateOperatorSearch(uiLayout *layout) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index fa3c12e158d..f566299960a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6702,7 +6702,7 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) } static void cache_file_layer_item(uiList *UNUSED(ui_list), - bContext *UNUSED(C), + const bContext *UNUSED(C), uiLayout *layout, PointerRNA *UNUSED(dataptr), PointerRNA *itemptr, diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.cc index e998eb6dbed..ec54b695cf7 100644 --- a/source/blender/editors/interface/interface_undo.c +++ b/source/blender/editors/interface/interface_undo.cc @@ -7,7 +7,7 @@ * Undo stack to use for UI widgets that manage their own editing state. */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" @@ -21,39 +21,39 @@ /** \name Text Field Undo Stack * \{ */ -typedef struct uiUndoStack_Text_State { +struct uiUndoStack_Text_State { struct uiUndoStack_Text_State *next, *prev; int cursor_index; char text[0]; -} uiUndoStack_Text_State; +}; -typedef struct uiUndoStack_Text { +struct uiUndoStack_Text { ListBase states; uiUndoStack_Text_State *current; -} uiUndoStack_Text; +}; static const char *ui_textedit_undo_impl(uiUndoStack_Text *stack, int *r_cursor_index) { /* Don't undo if no data has been pushed yet. */ - if (stack->current == NULL) { - return NULL; + if (stack->current == nullptr) { + return nullptr; } /* Travel backwards in the stack and copy information to the caller. */ - if (stack->current->prev != NULL) { + if (stack->current->prev != nullptr) { stack->current = stack->current->prev; *r_cursor_index = stack->current->cursor_index; return stack->current->text; } - return NULL; + return nullptr; } static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_index) { /* Don't redo if no data has been pushed yet. */ - if (stack->current == NULL) { - return NULL; + if (stack->current == nullptr) { + return nullptr; } /* Only redo if new data has not been entered since the last undo. */ @@ -63,7 +63,7 @@ static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_ *r_cursor_index = stack->current->cursor_index; return stack->current->text; } - return NULL; + return nullptr; } const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index) @@ -78,7 +78,7 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index) { /* Clear all redo actions from the current state. */ - if (stack->current != NULL) { + if (stack->current != nullptr) { while (stack->current->next) { uiUndoStack_Text_State *state = stack->current->next; BLI_remlink(&stack->states, state); @@ -88,7 +88,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor /* Create the new state. */ const int text_size = strlen(text) + 1; - stack->current = MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__); + stack->current = static_cast<uiUndoStack_Text_State *>( + MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__)); stack->current->cursor_index = cursor_index; memcpy(stack->current->text, text, text_size); BLI_addtail(&stack->states, stack->current); @@ -96,8 +97,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor uiUndoStack_Text *ui_textedit_undo_stack_create(void) { - uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__); - stack->current = NULL; + uiUndoStack_Text *stack = MEM_new<uiUndoStack_Text>(__func__); + stack->current = nullptr; BLI_listbase_clear(&stack->states); return stack; diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index a716c00d5d9..568ece00c4c 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -11,9 +11,9 @@ set(INC ../../io/collada ../../io/common ../../io/gpencil + ../../io/stl ../../io/usd ../../io/wavefront_obj - ../../io/stl ../../makesdna ../../makesrna ../../windowmanager @@ -33,8 +33,8 @@ set(SRC io_gpencil_utils.c io_obj.c io_ops.c - io_usd.c io_stl_ops.c + io_usd.c io_alembic.h io_cache.h @@ -42,8 +42,8 @@ set(SRC io_gpencil.h io_obj.h io_ops.h - io_usd.h io_stl_ops.h + io_usd.h ) set(LIB diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c index 9ac64407dcf..b6fecfaf94e 100644 --- a/source/blender/editors/io/io_gpencil_import.c +++ b/source/blender/editors/io/io_gpencil_import.c @@ -9,6 +9,8 @@ # include "BLI_path_util.h" +# include "MEM_guardedalloc.h" + # include "DNA_gpencil_types.h" # include "DNA_space_types.h" @@ -63,7 +65,8 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + if (!RNA_struct_property_is_set(op->ptr, "filepath") || + !(RNA_struct_find_property(op->ptr, "directory"))) { BKE_report(op->reports, RPT_ERROR, "No filename given"); return OPERATOR_CANCELLED; } @@ -75,9 +78,6 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) } View3D *v3d = get_invoke_view3d(C); - char filename[FILE_MAX]; - RNA_string_get(op->ptr, "filepath", filename); - /* Set flags. */ int flag = 0; @@ -101,13 +101,31 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) .resolution = resolution, }; - /* Do Import. */ - WM_cursor_wait(1); - const bool done = gpencil_io_import(filename, ¶ms); - WM_cursor_wait(0); - - if (!done) { - BKE_report(op->reports, RPT_WARNING, "Unable to import SVG"); + /* Loop all selected files to import them. All SVG imported shared the same import + * parameters, but they are created in separated grease pencil objects. */ + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { + char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0, NULL); + + if ((prop = RNA_struct_find_property(op->ptr, "files"))) { + char file_path[FILE_MAX]; + RNA_PROP_BEGIN (op->ptr, itemptr, prop) { + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL); + BLI_join_dirfile(file_path, sizeof(file_path), directory, filename); + MEM_freeN(filename); + + /* Do Import. */ + WM_cursor_wait(1); + RNA_string_get(&itemptr, "name", params.filename); + const bool done = gpencil_io_import(file_path, ¶ms); + WM_cursor_wait(0); + if (!done) { + BKE_reportf(op->reports, RPT_WARNING, "Unable to import '%s'", file_path); + } + } + RNA_PROP_END; + } + MEM_freeN(directory); } return OPERATOR_FINISHED; @@ -149,10 +167,11 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot) ot->check = wm_gpencil_import_svg_common_check; WM_operator_properties_filesel(ot, - FILE_TYPE_OBJECT_IO, + FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO, FILE_BLENDER, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS | + WM_FILESEL_DIRECTORY | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index b69cd8b8606..3608e162727 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -556,7 +556,7 @@ void paintvert_hide(bContext *C, Object *ob, const bool unselected) { Mesh *const me = BKE_mesh_from_object(ob); - if (me == NULL || me->totvert == 0) { + if (me == nullptr || me->totvert == 0) { return; } @@ -584,7 +584,7 @@ void paintvert_reveal(bContext *C, Object *ob, const bool select) { Mesh *const me = BKE_mesh_from_object(ob); - if (me == NULL || me->totvert == 0) { + if (me == nullptr || me->totvert == 0) { return; } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index ac5530c8ea9..2882bdfcbf2 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -603,7 +603,7 @@ static void bm_uv_assign_island(UvElementMap *element_map, int islandbufsize) { element->island = nisland; - map[element - element_map->buf] = islandbufsize; + map[element - element_map->storage] = islandbufsize; /* Copy *element to islandbuf[islandbufsize]. */ islandbuf[islandbufsize].l = element->l; @@ -620,16 +620,16 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, bool uv_selected, int cd_loop_uv_offset) { - int totuv = element_map->totalUVs; + int total_uvs = element_map->total_uvs; /* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */ - UvElement **head_table = MEM_mallocN(sizeof(*head_table) * totuv, "uv_island_head_table"); - for (int i = 0; i < totuv; i++) { - UvElement *head = element_map->buf + i; + UvElement **head_table = MEM_mallocN(sizeof(*head_table) * total_uvs, "uv_island_head_table"); + for (int i = 0; i < total_uvs; i++) { + UvElement *head = element_map->storage + i; if (head->separate) { UvElement *element = head; while (element) { - head_table[element - element_map->buf] = head; + head_table[element - element_map->storage] = head; element = element->next; if (element && element->separate) { break; @@ -641,12 +641,12 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, /* Depth first search the graph, building islands as we go. */ int nislands = 0; int islandbufsize = 0; - int stack_upper_bound = totuv; + int stack_upper_bound = total_uvs; UvElement **stack_uv = MEM_mallocN(sizeof(*stack_uv) * stack_upper_bound, "uv_island_element_stack"); int stacksize_uv = 0; - for (int i = 0; i < totuv; i++) { - UvElement *element = element_map->buf + i; + for (int i = 0; i < total_uvs; i++) { + UvElement *element = element_map->storage + i; if (element->island != INVALID_ISLAND) { /* Unique UV (element and all it's children) are already part of an island. */ continue; @@ -676,7 +676,7 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, if (!uv_selected || uvedit_edge_select_test(scene, element->l, cd_loop_uv_offset)) { UvElement *next = BM_uv_element_get(element_map, element->l->next->f, element->l->next); if (next->island == INVALID_ISLAND) { - UvElement *tail = head_table[next - element_map->buf]; + UvElement *tail = head_table[next - element_map->storage]; stack_uv[stacksize_uv++] = tail; while (tail) { bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++); @@ -692,7 +692,7 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, if (!uv_selected || uvedit_edge_select_test(scene, element->l->prev, cd_loop_uv_offset)) { UvElement *prev = BM_uv_element_get(element_map, element->l->prev->f, element->l->prev); if (prev->island == INVALID_ISLAND) { - UvElement *tail = head_table[prev - element_map->buf]; + UvElement *tail = head_table[prev - element_map->storage]; stack_uv[stacksize_uv++] = tail; while (tail) { bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++); @@ -713,7 +713,7 @@ static int bm_uv_edge_select_build_islands(UvElementMap *element_map, } nislands++; } - BLI_assert(islandbufsize == totuv); + BLI_assert(islandbufsize == total_uvs); MEM_SAFE_FREE(stack_uv); MEM_SAFE_FREE(head_table); @@ -732,26 +732,18 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, BMVert *ev; BMFace *efa; - BMLoop *l; BMIter iter, liter; - /* vars from original func */ - UvElementMap *element_map; - UvElement *buf; - bool *winding = NULL; BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - MLoopUV *luv; - int totverts, totfaces, i, totuv, j; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset < 0) { + return NULL; + } BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - totfaces = bm->totface; - totverts = bm->totvert; - totuv = 0; - - /* generate UvElement array */ + /* Count total uvs. */ + int totuv = 0; BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { continue; @@ -765,6 +757,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, totuv += efa->len; } else { + BMLoop *l; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { totuv++; @@ -777,17 +770,17 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, return NULL; } - element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); - element_map->totalUVs = totuv; - element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, - "UvElementVerts"); - buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, - "UvElement"); + UvElementMap *element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); + element_map->total_uvs = totuv; + element_map->vertex = (UvElement **)MEM_callocN(sizeof(*element_map->vertex) * bm->totvert, + "UvElementVerts"); + element_map->storage = (UvElement *)MEM_callocN(sizeof(*element_map->storage) * totuv, + "UvElement"); - if (use_winding) { - winding = MEM_callocN(sizeof(*winding) * totfaces, "winding"); - } + bool *winding = use_winding ? MEM_callocN(sizeof(*winding) * bm->totface, "winding") : NULL; + UvElement *buf = element_map->storage; + int j; BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) { if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { @@ -804,18 +797,20 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len); } + int i; + BMLoop *l; BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { continue; } buf->l = l; - buf->separate = 0; buf->island = INVALID_ISLAND; buf->loop_of_poly_index = i; - buf->next = element_map->vert[BM_elem_index_get(l->v)]; - element_map->vert[BM_elem_index_get(l->v)] = buf; + /* Insert to head of linked list associated with BMVert. */ + buf->next = element_map->vertex[BM_elem_index_get(l->v)]; + element_map->vertex[BM_elem_index_get(l->v)] = buf; if (use_winding) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -830,34 +825,33 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, } } - /* sort individual uvs for each vert */ - BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) { - UvElement *newvlist = NULL, *vlist = element_map->vert[i]; - UvElement *iterv, *v, *lastv, *next; - const float *uv, *uv2; - bool uv_vert_sel, uv2_vert_sel; - + /* For each BMVert, sort associated linked list into unique uvs. */ + int ev_index; + BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) { + UvElement *newvlist = NULL; + UvElement *vlist = element_map->vertex[ev_index]; while (vlist) { - v = vlist; + + /* Detach head from unsorted list. */ + UvElement *v = vlist; vlist = vlist->next; v->next = newvlist; newvlist = v; - l = v->l; - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv = luv->uv; - uv_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + luv = BM_ELEM_CD_GET_VOID_P(v->l, cd_loop_uv_offset); + const float *uv = luv->uv; + bool uv_vert_sel = uvedit_uv_select_test(scene, v->l, cd_loop_uv_offset); - lastv = NULL; - iterv = vlist; + UvElement *lastv = NULL; + UvElement *iterv = vlist; + /* Scan through unsorted list, finding UvElements which match `v`. */ while (iterv) { - next = iterv->next; + UvElement *next = iterv->next; - l = iterv->l; - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - uv2 = luv->uv; - uv2_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + luv = BM_ELEM_CD_GET_VOID_P(iterv->l, cd_loop_uv_offset); + const float *uv2 = luv->uv; + const bool uv2_vert_sel = uvedit_uv_select_test(scene, iterv->l, cd_loop_uv_offset); /* Check if the uv loops share the same selection state (if not, they are not connected as * they have been ripped or other edit commands have separated them). */ @@ -882,32 +876,30 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, iterv = next; } - newvlist->separate = 1; + element_map->total_unique_uvs++; + newvlist->separate = true; } - element_map->vert[i] = newvlist; + /* Write back sorted list. */ + element_map->vertex[ev_index] = newvlist; } - if (use_winding) { - MEM_freeN(winding); - } + MEM_SAFE_FREE(winding); if (do_islands) { uint *map; - BMFace **stack; - int stacksize = 0; UvElement *islandbuf; - /* island number for faces */ - int *island_number = NULL; int nislands = 0, islandbufsize = 0; /* map holds the map from current vmap->buf to the new, sorted map */ map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap"); - stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack"); + BMFace **stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack"); islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer"); - island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face"); - copy_vn_i(island_number, totfaces, INVALID_ISLAND); + /* Island number for BMFaces. */ + int *island_number = MEM_callocN(sizeof(*island_number) * bm->totface, + "uv_island_number_face"); + copy_vn_i(island_number, bm->totface, INVALID_ISLAND); const bool use_uv_edge_connectivity = scene->toolsettings->uv_flag & UV_SYNC_SELECTION ? scene->toolsettings->selectmode & SCE_SELECT_EDGE : @@ -920,24 +912,26 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. * Now we should sort uv's in islands. */ - for (i = 0; i < totuv; i++) { - if (element_map->buf[i].island == INVALID_ISLAND) { - element_map->buf[i].island = nislands; - stack[0] = element_map->buf[i].l->f; + for (int i = 0; i < totuv; i++) { + if (element_map->storage[i].island == INVALID_ISLAND) { + int stacksize = 0; + element_map->storage[i].island = nislands; + stack[0] = element_map->storage[i].l->f; island_number[BM_elem_index_get(stack[0])] = nislands; stacksize = 1; while (stacksize > 0) { efa = stack[--stacksize]; + BMLoop *l; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { continue; } - UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)]; + UvElement *initelement = element_map->vertex[BM_elem_index_get(l->v)]; - for (element = initelement; element; element = element->next) { + for (UvElement *element = initelement; element; element = element->next) { if (element->separate) { initelement = element; } @@ -968,26 +962,26 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, } } - MEM_freeN(island_number); + MEM_SAFE_FREE(island_number); /* remap */ - for (i = 0; i < bm->totvert; i++) { + for (int i = 0; i < bm->totvert; i++) { /* important since we may do selection only. Some of these may be NULL */ - if (element_map->vert[i]) { - element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]]; + if (element_map->vertex[i]) { + element_map->vertex[i] = &islandbuf[map[element_map->vertex[i] - element_map->storage]]; } } element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices"); j = 0; - for (i = 0; i < totuv; i++) { - UvElement *element = element_map->buf[i].next; + for (int i = 0; i < totuv; i++) { + UvElement *element = element_map->storage[i].next; if (element == NULL) { islandbuf[map[i]].next = NULL; } else { - islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]]; + islandbuf[map[i]].next = &islandbuf[map[element - element_map->storage]]; } if (islandbuf[i].island != j) { @@ -996,16 +990,23 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, } } - MEM_freeN(element_map->buf); - - element_map->buf = islandbuf; + MEM_SAFE_FREE(element_map->storage); + element_map->storage = islandbuf; + islandbuf = NULL; element_map->totalIslands = nislands; - MEM_freeN(stack); - MEM_freeN(map); + MEM_SAFE_FREE(stack); + MEM_SAFE_FREE(map); } BLI_buffer_free(&tf_uv_buf); + element_map->total_unique_uvs = 0; + for (int i = 0; i < element_map->total_uvs; i++) { + if (element_map->storage[i].separate) { + element_map->total_unique_uvs++; + } + } + return element_map; } @@ -1025,30 +1026,35 @@ void BM_uv_vert_map_free(UvVertMap *vmap) void BM_uv_element_map_free(UvElementMap *element_map) { if (element_map) { - if (element_map->vert) { - MEM_freeN(element_map->vert); - } - if (element_map->buf) { - MEM_freeN(element_map->buf); - } - if (element_map->islandIndices) { - MEM_freeN(element_map->islandIndices); - } - MEM_freeN(element_map); + MEM_SAFE_FREE(element_map->storage); + MEM_SAFE_FREE(element_map->vertex); + MEM_SAFE_FREE(element_map->islandIndices); + MEM_SAFE_FREE(element_map); } } -UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) +UvElement *BM_uv_element_get(UvElementMap *element_map, BMFace *efa, BMLoop *l) { - for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; element; element = element->next) { + UvElement *element = element_map->vertex[BM_elem_index_get(l->v)]; + while (element) { if (element->l->f == efa) { return element; } + element = element->next; } return NULL; } +UvElement *BM_uv_element_get_head(UvElementMap *element_map, UvElement *child) +{ + if (!child) { + return NULL; + } + + return element_map->vertex[BM_elem_index_get(child->l->v)]; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 67834bf05ce..971fab1508e 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -444,44 +444,6 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name) return (layer != nullptr); } -bool ED_mesh_color_remove_index(Mesh *me, const int n) -{ - CustomData *ldata = GET_CD_DATA(me, ldata); - CustomDataLayer *cdl; - int index; - - index = CustomData_get_layer_index_n(ldata, CD_PROP_BYTE_COLOR, n); - cdl = (index == -1) ? nullptr : &ldata->layers[index]; - - if (!cdl) { - return false; - } - - delete_customdata_layer(me, cdl); - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); - - return true; -} -bool ED_mesh_color_remove_active(Mesh *me) -{ - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR); - if (n != -1) { - return ED_mesh_color_remove_index(me, n); - } - return false; -} -bool ED_mesh_color_remove_named(Mesh *me, const char *name) -{ - CustomData *ldata = GET_CD_DATA(me, ldata); - const int n = CustomData_get_named_layer(ldata, CD_PROP_BYTE_COLOR, name); - if (n != -1) { - return ED_mesh_color_remove_index(me, n); - } - return false; -} - /*********************** General poll ************************/ static bool layers_poll(bContext *C) @@ -494,25 +456,7 @@ static bool layers_poll(bContext *C) /*********************** Sculpt Vertex colors operators ************************/ -static bool sculpt_vertex_color_remove_poll(bContext *C) -{ - if (!layers_poll(C)) { - return false; - } - - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - CustomData *vdata = GET_CD_DATA(me, vdata); - const int active = CustomData_get_active_layer(vdata, CD_PROP_COLOR); - if (active != -1) { - return true; - } - - return false; -} - -int ED_mesh_sculpt_color_add( - Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports) +int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool do_init, ReportList *reports) { /* NOTE: keep in sync with #ED_mesh_uv_add. */ @@ -536,7 +480,7 @@ int ED_mesh_sculpt_color_add( const int layernum_dst = CustomData_get_active_layer(&em->bm->vdata, CD_PROP_COLOR); BM_data_layer_copy(em->bm, &em->bm->vdata, CD_PROP_COLOR, layernum_dst, layernum); } - if (active_set || layernum == 0) { + if (layernum == 0) { CustomData_set_layer_active(&em->bm->vdata, CD_PROP_COLOR, layernum); } } @@ -559,7 +503,7 @@ int ED_mesh_sculpt_color_add( &me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name); } - if (active_set || layernum == 0) { + if (layernum == 0) { CustomData_set_layer_active(&me->vdata, CD_PROP_COLOR, layernum); } @@ -572,58 +516,6 @@ int ED_mesh_sculpt_color_add( return layernum; } -bool ED_mesh_sculpt_color_ensure(Mesh *me, const char *name) -{ - BLI_assert(me->edit_mesh == nullptr); - - if (me->totvert && !CustomData_has_layer(&me->vdata, CD_PROP_COLOR)) { - CustomData_add_layer_named(&me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name); - BKE_mesh_update_customdata_pointers(me, true); - } - - DEG_id_tag_update(&me->id, 0); - - return (me->mloopcol != nullptr); -} - -bool ED_mesh_sculpt_color_remove_index(Mesh *me, const int n) -{ - CustomData *vdata = GET_CD_DATA(me, vdata); - CustomDataLayer *cdl; - int index; - - index = CustomData_get_layer_index_n(vdata, CD_PROP_COLOR, n); - cdl = (index == -1) ? nullptr : &vdata->layers[index]; - - if (!cdl) { - return false; - } - - delete_customdata_layer(me, cdl); - DEG_id_tag_update(&me->id, 0); - WM_main_add_notifier(NC_GEOM | ND_DATA, me); - - return true; -} -bool ED_mesh_sculpt_color_remove_active(Mesh *me) -{ - CustomData *vdata = GET_CD_DATA(me, vdata); - const int n = CustomData_get_active_layer(vdata, CD_PROP_COLOR); - if (n != -1) { - return ED_mesh_sculpt_color_remove_index(me, n); - } - return false; -} -bool ED_mesh_sculpt_color_remove_named(Mesh *me, const char *name) -{ - CustomData *vdata = GET_CD_DATA(me, vdata); - const int n = CustomData_get_named_layer(vdata, CD_PROP_COLOR, name); - if (n != -1) { - return ED_mesh_sculpt_color_remove_index(me, n); - } - return false; -} - /*********************** UV texture operators ************************/ static bool uv_texture_remove_poll(bContext *C) @@ -709,135 +601,6 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/*********************** vertex color operators ************************/ - -static bool vertex_color_remove_poll(bContext *C) -{ - if (!layers_poll(C)) { - return false; - } - - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - CustomData *ldata = GET_CD_DATA(me, ldata); - const int active = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR); - if (active != -1) { - return true; - } - - return false; -} - -static int mesh_vertex_color_add_exec(bContext *C, wmOperator *op) -{ - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - - if (ED_mesh_color_add(me, nullptr, true, true, op->reports) == -1) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -void MESH_OT_vertex_color_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Vertex Color"; - ot->description = "Add vertex color layer"; - ot->idname = "MESH_OT_vertex_color_add"; - - /* api callbacks */ - ot->poll = layers_poll; - ot->exec = mesh_vertex_color_add_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int mesh_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - - if (!ED_mesh_color_remove_active(me)) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -void MESH_OT_vertex_color_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Vertex Color"; - ot->description = "Remove vertex color layer"; - ot->idname = "MESH_OT_vertex_color_remove"; - - /* api callbacks */ - ot->exec = mesh_vertex_color_remove_exec; - ot->poll = vertex_color_remove_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/*********************** Sculpt Vertex Color Operators ************************/ - -static int mesh_sculpt_vertex_color_add_exec(bContext *C, wmOperator *op) -{ - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - - if (ED_mesh_sculpt_color_add(me, nullptr, true, true, op->reports) == -1) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -void MESH_OT_sculpt_vertex_color_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Sculpt Vertex Color"; - ot->description = "Add vertex color layer"; - ot->idname = "MESH_OT_sculpt_vertex_color_add"; - - /* api callbacks */ - ot->poll = layers_poll; - ot->exec = mesh_sculpt_vertex_color_add_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int mesh_sculpt_vertex_color_remove_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = ED_object_context(C); - Mesh *me = static_cast<Mesh *>(ob->data); - - if (!ED_mesh_sculpt_color_remove_active(me)) { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -void MESH_OT_sculpt_vertex_color_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Sculpt Vertex Color"; - ot->description = "Remove vertex color layer"; - ot->idname = "MESH_OT_sculpt_vertex_color_remove"; - - /* api callbacks */ - ot->exec = mesh_sculpt_vertex_color_remove_exec; - ot->poll = sculpt_vertex_color_remove_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /* *** CustomData clear functions, we need an operator for each *** */ static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type) diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 303234df48c..7c8dbffeb31 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -308,10 +308,6 @@ void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot); void MESH_OT_uv_texture_add(struct wmOperatorType *ot); void MESH_OT_uv_texture_remove(struct wmOperatorType *ot); -void MESH_OT_vertex_color_add(struct wmOperatorType *ot); -void MESH_OT_vertex_color_remove(struct wmOperatorType *ot); -void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot); -void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot); void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot); void MESH_OT_customdata_skin_add(struct wmOperatorType *ot); void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index be7f60b0da0..b9e78740e3c 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -134,10 +134,6 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_uv_texture_add); WM_operatortype_append(MESH_OT_uv_texture_remove); - WM_operatortype_append(MESH_OT_vertex_color_add); - WM_operatortype_append(MESH_OT_vertex_color_remove); - WM_operatortype_append(MESH_OT_sculpt_vertex_color_add); - WM_operatortype_append(MESH_OT_sculpt_vertex_color_remove); WM_operatortype_append(MESH_OT_customdata_mask_clear); WM_operatortype_append(MESH_OT_customdata_skin_add); WM_operatortype_append(MESH_OT_customdata_skin_clear); diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index d44af45a015..ac4fb40d832 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -582,7 +582,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev mat4_to_size(scale, active_object->obmat); invert_v3(scale); size_to_mat4(scale_mat, scale); - + mul_m4_m4_pre(cd->text_mat, scale_mat); /* Write the text position into the matrix. */ diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index e8ceb97ed7a..1ce90849a88 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -21,6 +21,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_attribute.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_dynamicpaint.h" @@ -233,7 +234,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op) ED_mesh_color_add(ob->data, name, true, true, op->reports); } else { - ED_mesh_color_remove_named(ob->data, name); + BKE_id_attribute_remove(ob->data, name, NULL); } } /* Vertex Weight Layer */ diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index 77ad23f1e3f..e91bffce2c2 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -278,19 +278,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender) static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr) { - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = oglrender->scene; - ARegion *region = oglrender->region; - View3D *v3d = oglrender->v3d; - RegionView3D *rv3d = oglrender->rv3d; Object *camera = nullptr; int sizex = oglrender->sizex; int sizey = oglrender->sizey; - const short view_context = (v3d != nullptr); - bool draw_sky = (scene->r.alphamode == R_ADDSKY); - float *rectf = nullptr; - uchar *rect = nullptr; - const char *viewname = RE_GetActiveRenderView(oglrender->re); ImBuf *ibuf_result = nullptr; if (oglrender->is_sequencer) { @@ -301,7 +292,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id]; if (ibuf) { - ImBuf *out = IMB_dupImBuf(ibuf); + ibuf_result = IMB_dupImBuf(ibuf); IMB_freeImBuf(ibuf); /* OpenGL render is considered to be preview and should be * as fast as possible. So currently we're making sure sequencer @@ -310,25 +301,21 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R * TODO(sergey): In the case of output to float container (EXR) * it actually makes sense to keep float buffer instead. */ - if (out->rect_float != nullptr) { - IMB_rect_from_float(out); - imb_freerectfloatImBuf(out); + if (ibuf_result->rect_float != nullptr) { + IMB_rect_from_float(ibuf_result); + imb_freerectfloatImBuf(ibuf_result); } - BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); - RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id); - IMB_freeImBuf(out); + BLI_assert((sizex == ibuf->x) && (sizey == ibuf->y)); } else if (gpd) { /* If there are no strips, Grease Pencil still needs a buffer to draw on */ - ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect); - RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id); - IMB_freeImBuf(out); + ibuf_result = IMB_allocImBuf(sizex, sizey, 32, IB_rect); } if (gpd) { int i; uchar *gp_rect; - uchar *render_rect = (uchar *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; + uchar *render_rect = (uchar *)ibuf_result->rect; DRW_opengl_context_enable(); GPU_offscreen_bind(oglrender->ofs, true); @@ -359,10 +346,16 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R } else { /* shouldn't suddenly give errors mid-render but possible */ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); char err_out[256] = "unknown"; ImBuf *ibuf_view; + bool draw_sky = (scene->r.alphamode == R_ADDSKY); const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; - if (view_context) { + const char *viewname = RE_GetActiveRenderView(oglrender->re); + View3D *v3d = oglrender->v3d; + + if (v3d != nullptr) { + ARegion *region = oglrender->region; ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph, scene, static_cast<eDrawType>(v3d->shading.type), @@ -378,7 +371,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R err_out); /* for stamp only */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) { camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); } } @@ -388,8 +381,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R nullptr, OB_SOLID, scene->camera, - oglrender->sizex, - oglrender->sizey, + sizex, + sizey, IB_rectfloat, V3D_OFSDRAW_SHOW_ANNOTATION, alpha_mode, @@ -401,12 +394,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_view) { ibuf_result = ibuf_view; - if (ibuf_view->rect_float) { - rectf = ibuf_view->rect_float; - } - else { - rect = (uchar *)ibuf_view->rect; - } } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); @@ -415,6 +402,14 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_result != nullptr) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { + float *rectf = nullptr; + uchar *rect = nullptr; + if (ibuf_result->rect_float) { + rectf = ibuf_result->rect_float; + } + else { + rect = (uchar *)ibuf_result->rect; + } BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id); diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 97bbcaa102f..cd0a05f02bc 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -1771,7 +1771,7 @@ PreviewLoadJob &PreviewLoadJob::ensure_job(wmWindowManager *wm, wmWindow *win) WM_jobs_start(wm, wm_job); } - return *reinterpret_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job)); + return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job)); } void PreviewLoadJob::load_jobless(PreviewImage *preview, const eIconSizes icon_size) @@ -1807,11 +1807,11 @@ void PreviewLoadJob::run_fn(void *customdata, short *do_update, float *UNUSED(progress)) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); IMB_thumb_locks_acquire(); - while (RequestedPreview *request = reinterpret_cast<RequestedPreview *>( + while (RequestedPreview *request = static_cast<RequestedPreview *>( BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100))) { if (*stop) { break; @@ -1864,7 +1864,7 @@ void PreviewLoadJob::finish_request(RequestedPreview &request) void PreviewLoadJob::update_fn(void *customdata) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); for (auto request_it = job_data->requested_previews_.begin(); request_it != job_data->requested_previews_.end();) { @@ -1884,7 +1884,7 @@ void PreviewLoadJob::update_fn(void *customdata) void PreviewLoadJob::end_fn(void *customdata) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); /* Finish any possibly remaining queued previews. */ for (RequestedPreview &request : job_data->requested_previews_) { @@ -1895,7 +1895,7 @@ void PreviewLoadJob::end_fn(void *customdata) void PreviewLoadJob::free_fn(void *customdata) { - MEM_delete(reinterpret_cast<PreviewLoadJob *>(customdata)); + MEM_delete(static_cast<PreviewLoadJob *>(customdata)); } static void icon_preview_free(void *customdata) diff --git a/source/blender/editors/render/render_update.cc b/source/blender/editors/render/render_update.cc index 3d26e764211..7cefcf9815e 100644 --- a/source/blender/editors/render/render_update.cc +++ b/source/blender/editors/render/render_update.cc @@ -95,20 +95,20 @@ void ED_render_view3d_update(Depsgraph *depsgraph, CTX_free(C); } - else { - RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); - if (updated) { - DRWUpdateContext drw_context = {nullptr}; - drw_context.bmain = bmain; - drw_context.depsgraph = depsgraph; - drw_context.scene = scene; - drw_context.view_layer = view_layer; - drw_context.region = region; - drw_context.v3d = v3d; - drw_context.engine_type = engine_type; - DRW_notify_view_update(&drw_context); - } + + if (!updated) { + continue; } + + DRWUpdateContext drw_context = {nullptr}; + drw_context.bmain = bmain; + drw_context.depsgraph = depsgraph; + drw_context.scene = scene; + drw_context.view_layer = view_layer; + drw_context.region = region; + drw_context.v3d = v3d; + drw_context.engine_type = ED_view3d_engine_type(scene, v3d->shading.type); + DRW_notify_view_update(&drw_context); } } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 0d6b6ee1d78..83e6c837eac 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -1032,15 +1032,13 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C, CTX_data_id_pointer_set(result, (ID *)action); break; } - else { - if (editable && ID_IS_LINKED(action)) { - continue; - } + if (editable && ID_IS_LINKED(action)) { + continue; + } - /* Add the action to the output list if not already added. */ - if (BLI_gset_add(seen_set, action)) { - CTX_data_id_list_add(result, &action->id); - } + /* Add the action to the output list if not already added. */ + if (BLI_gset_add(seen_set, action)) { + CTX_data_id_list_add(result, &action->id); } } } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index edb0f1cda4d..b170280ccf3 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -37,8 +37,8 @@ set(SRC curves_sculpt_ops.cc curves_sculpt_pinch.cc curves_sculpt_puff.cc - curves_sculpt_selection_paint.cc curves_sculpt_selection.cc + curves_sculpt_selection_paint.cc curves_sculpt_slide.cc curves_sculpt_smooth.cc curves_sculpt_snake_hook.cc diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc index 5bfc8ccc667..a955a074df2 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc @@ -67,10 +67,11 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, return selection.get_internal_single() <= 0.0f ? IndexMask(0) : IndexMask(curves.curves_num()); } + const Span<float> point_selection_span = selection.get_internal_span(); return index_mask_ops::find_indices_based_on_predicate( curves.curves_range(), 512, r_indices, [&](const int curve_i) { for (const int i : curves.points_for_curve(curve_i)) { - if (selection[i] > 0.0f) { + if (point_selection_span[i] > 0.0f) { return true; } } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index c5ebcf870a3..577540725af 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1145,11 +1145,10 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, } GPU_line_width(1.0f); - if (ss->preview_vert_index_count > 0) { - immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count); - for (int i = 0; i < ss->preview_vert_index_count; i++) { - immVertex3fv(gpuattr, - SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_index_list[i])); + if (ss->preview_vert_count > 0) { + immBegin(GPU_PRIM_LINES, ss->preview_vert_count); + for (int i = 0; i < ss->preview_vert_count; i++) { + immVertex3fv(gpuattr, SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_list[i])); } immEnd(); } @@ -1209,7 +1208,7 @@ typedef struct PaintCursorContext { /* Sculpt related data. */ Sculpt *sd; SculptSession *ss; - int prev_active_vertex_index; + PBVHVertRef prev_active_vertex; bool is_stroke_active; bool is_cursor_over_mesh; bool is_multires; @@ -1366,7 +1365,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to * work correctly */ - pcontext->prev_active_vertex_index = ss->active_vertex_index; + pcontext->prev_active_vertex = ss->active_vertex; if (!ups->stroke_active) { pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update( C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); @@ -1549,7 +1548,7 @@ static void paint_cursor_preview_boundary_data_update(PaintCursorContext *pconte } ss->boundary_preview = SCULPT_boundary_data_init( - pcontext->vc.obact, pcontext->brush, ss->active_vertex_index, pcontext->radius); + pcontext->vc.obact, pcontext->brush, ss->active_vertex, pcontext->radius); } static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *pcontext) @@ -1575,8 +1574,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * paint_cursor_update_object_space_radius(pcontext); - const bool update_previews = pcontext->prev_active_vertex_index != - SCULPT_active_vertex_get(pcontext->ss); + const bool update_previews = pcontext->prev_active_vertex.i != + SCULPT_active_vertex_get(pcontext->ss).i; /* Setup drawing. */ wmViewport(&pcontext->region->winrct); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 9449cc6eb8d..3e5ad9bdc2d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1223,12 +1223,12 @@ static VertSeam *find_adjacent_seam(const ProjPaintState *ps, /* Circulate through the (sorted) vert seam array, in the direction of the seam normal, * until we find the first opposing seam, matching in UV space. */ if (seam->normal_cw) { - LISTBASE_CIRCULAR_BACKWARD_BEGIN (vert_seams, adjacent, seam) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN (VertSeam *, vert_seams, adjacent, seam) { if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) { break; } } - LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam); + LISTBASE_CIRCULAR_BACKWARD_END(VertSeam *, vert_seams, adjacent, seam); } else { LISTBASE_CIRCULAR_FORWARD_BEGIN (vert_seams, adjacent, seam) { diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index b861d0c84da..2e57886fd95 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -663,7 +663,7 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd) { float vertex_normal[3]; - SCULPT_vertex_normal_get(sgcontext->ss, vd->index, vertex_normal); + SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal); float dot = dot_v3v3(sgcontext->view_normal, vertex_normal); const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f); @@ -743,7 +743,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { - SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id); + SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id); any_updated = true; } } @@ -1025,7 +1025,9 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) trim_operation->depth_back = -FLT_MAX; for (int i = 0; i < totvert; i++) { - const float *vco = SCULPT_vertex_co_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + const float *vco = SCULPT_vertex_co_get(ss, vertex); /* Convert the coordinates to world space to calculate the depth. When generating the trimming * mesh, coordinates are first calculated in world space, then converted to object space to * store them. */ @@ -1437,7 +1439,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata, } add_v3_v3(vd.co, disp); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(sgcontext->ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(sgcontext->ss->pbvh, vd.vertex); } any_updated = true; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index aa151b2e678..8df5b093560 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -122,22 +122,22 @@ int SCULPT_vertex_count_get(SculptSession *ss) return 0; } -const float *SCULPT_vertex_co_get(SculptSession *ss, int index) +const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { if (ss->shapekey_active || ss->deform_modifiers_active) { const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); - return mverts[index].co; + return mverts[vertex.i].co; } - return ss->mvert[index].co; + return ss->mvert[vertex.i].co; } case PBVH_BMESH: - return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co; + return ((BMVert *)vertex.i)->co; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index)); } @@ -158,31 +158,33 @@ bool SCULPT_has_colors(const SculptSession *ss) return ss->vcol || ss->mcol; } -void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]) +void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]) { - BKE_pbvh_vertex_color_get(ss->pbvh, index, r_color); + BKE_pbvh_vertex_color_get(ss->pbvh, vertex, r_color); } -void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]) +void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]) { - BKE_pbvh_vertex_color_set(ss->pbvh, index, color); + BKE_pbvh_vertex_color_set(ss->pbvh, vertex, color); } -void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) +void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh); - copy_v3_v3(no, vert_normals[index]); + copy_v3_v3(no, vert_normals[vertex.i]); break; } - case PBVH_BMESH: - copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); + case PBVH_BMESH: { + BMVert *v = (BMVert *)vertex.i; + copy_v3_v3(no, v->no); break; + } case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index))); break; @@ -190,42 +192,42 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) } } -const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index) +const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex) { if (ss->persistent_base) { - return ss->persistent_base[index].co; + return ss->persistent_base[BKE_pbvh_vertex_to_index(ss->pbvh, vertex)].co; } - return SCULPT_vertex_co_get(ss, index); + return SCULPT_vertex_co_get(ss, vertex); } -const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index) +const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex) { - /* Always grab active shape key if the sculpt happens on shapekey. */ - if (ss->shapekey_active) { - const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); - return mverts[index].co; - } + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + /* Always grab active shape key if the sculpt happens on shapekey. */ + if (ss->shapekey_active) { + const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); + return mverts[vertex.i].co; + } - /* Sculpting on the base mesh. */ - if (ss->mvert) { - return ss->mvert[index].co; + /* Sculpting on the base mesh. */ + return ss->mvert[vertex.i].co; } /* Everything else, such as sculpting on multires. */ - return SCULPT_vertex_co_get(ss, index); + return SCULPT_vertex_co_get(ss, vertex); } -void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]) +void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3]) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_BMESH: - copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, vertex)); break; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, @@ -236,30 +238,30 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3] } } -void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]) +void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]) { if (ss->persistent_base) { - copy_v3_v3(no, ss->persistent_base[index].no); + copy_v3_v3(no, ss->persistent_base[vertex.i].no); return; } - SCULPT_vertex_normal_get(ss, index, no); + SCULPT_vertex_normal_get(ss, vertex, no); } -float SCULPT_vertex_mask_get(SculptSession *ss, int index) +float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex) { BMVert *v; float *mask; switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->vmask[index]; + return ss->vmask[vertex.i]; case PBVH_BMESH: - v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); + v = (BMVert *)vertex.i; mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); return *mask; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index)); } @@ -268,12 +270,13 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index) return 0.0f; } -int SCULPT_active_vertex_get(SculptSession *ss) +PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss) { if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) { - return ss->active_vertex_index; + return ss->active_vertex; } - return 0; + + return BKE_pbvh_make_vref(PBVH_REF_NONE); } const float *SCULPT_active_vertex_co_get(SculptSession *ss) @@ -338,32 +341,33 @@ int SCULPT_active_face_set_get(SculptSession *ss) return SCULPT_FACE_SET_NONE; } -void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible) +void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - SET_FLAG_FROM_TEST(ss->mvert[index].flag, !visible, ME_HIDE); - BKE_pbvh_vert_tag_update_normal(ss->pbvh, index); + SET_FLAG_FROM_TEST(ss->mvert[vertex.i].flag, !visible, ME_HIDE); break; - case PBVH_BMESH: - BM_elem_flag_set(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN, !visible); + case PBVH_BMESH: { + BMVert *v = (BMVert *)vertex.i; + BM_elem_flag_set(v, BM_ELEM_HIDDEN, !visible); break; + } case PBVH_GRIDS: break; } } -bool SCULPT_vertex_visible_get(SculptSession *ss, int index) +bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return !(ss->mvert[index].flag & ME_HIDE); + return !(ss->mvert[vertex.i].flag & ME_HIDE); case PBVH_BMESH: - return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN); + return !BM_elem_flag_test((BMVert *)vertex.i, BM_ELEM_HIDDEN); case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh); if (grid_hidden && grid_hidden[grid_index]) { return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index); @@ -436,12 +440,12 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) } } -bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index) +bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { return true; } @@ -456,12 +460,12 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index) return true; } -bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) +bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] < 0) { return false; } @@ -472,7 +476,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index] > 0; } @@ -480,12 +484,12 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) return true; } -void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) +void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { ss->face_sets[vert_map->indices[j]] = abs(face_set); } @@ -495,7 +499,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) break; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); if (ss->face_sets[face_index] > 0) { ss->face_sets[face_index] = abs(face_set); @@ -505,13 +509,13 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) } } -int SCULPT_vertex_face_set_get(SculptSession *ss, int index) +int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; + MeshElemMap *vert_map = &ss->pmap[vertex.i]; int face_set = 0; - for (int i = 0; i < ss->pmap[index].count; i++) { + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] > face_set) { face_set = abs(ss->face_sets[vert_map->indices[i]]); } @@ -522,7 +526,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index) return 0; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index]; } @@ -530,12 +534,12 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index) return 0; } -bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set) +bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int i = 0; i < ss->pmap[index].count; i++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] == face_set) { return true; } @@ -546,7 +550,7 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set) return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index] == face_set; } @@ -574,11 +578,11 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob) } static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss, - int index) + PBVHVertRef vertex) { - MeshElemMap *vert_map = &ss->pmap[index]; - const bool visible = SCULPT_vertex_visible_get(ss, index); - for (int i = 0; i < ss->pmap[index].count; i++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + const bool visible = SCULPT_vertex_visible_get(ss, vertex); + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (visible) { ss->face_sets[vert_map->indices[i]] = abs(ss->face_sets[vert_map->indices[i]]); } @@ -596,7 +600,7 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) bool poly_visible = true; for (int l = 0; l < poly->totloop; l++) { MLoop *loop = &ss->mloop[poly->loopstart + l]; - if (!SCULPT_vertex_visible_get(ss, (int)loop->v)) { + if (!SCULPT_vertex_visible_get(ss, BKE_pbvh_make_vref(loop->v))) { poly_visible = false; } } @@ -659,18 +663,18 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss return true; } -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index) +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - return sculpt_check_unique_face_set_in_base_mesh(ss, index); + return sculpt_check_unique_face_set_in_base_mesh(ss, vertex.i); } case PBVH_BMESH: return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; const SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, .y = vertex_index / key->grid_size}; @@ -714,10 +718,12 @@ int SCULPT_face_set_next_available_get(SculptSession *ss) #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 -static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) +static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, + PBVHVertRef neighbor, + int neighbor_index) { for (int i = 0; i < iter->size; i++) { - if (iter->neighbors[i] == neighbor_index) { + if (iter->neighbors[i].i == neighbor.i) { return; } } @@ -726,63 +732,74 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; if (iter->neighbors == iter->neighbors_fixed) { - iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"); - memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size); + iter->neighbors = MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(PBVHVertRef) * iter->size); } else { iter->neighbors = MEM_reallocN_id( - iter->neighbors, iter->capacity * sizeof(int), "neighbor array"); + iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + } + + if (iter->neighbor_indices == iter->neighbor_indices_fixed) { + iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"); + memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size); + } + else { + iter->neighbor_indices = MEM_reallocN_id( + iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array"); } } - iter->neighbors[iter->size] = neighbor_index; + iter->neighbors[iter->size] = neighbor; + iter->neighbor_indices[iter->size] = neighbor_index; iter->size++; } -static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss, - int index, - SculptVertexNeighborIter *iter) +static void sculpt_vertex_neighbors_get_bmesh(PBVHVertRef vertex, SculptVertexNeighborIter *iter) { - BMVert *v = BM_vert_at_index(ss->bm, index); + BMVert *v = (BMVert *)vertex.i; BMIter liter; BMLoop *l; iter->size = 0; iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { const BMVert *adj_v[2] = {l->prev->v, l->next->v}; for (int i = 0; i < ARRAY_SIZE(adj_v); i++) { const BMVert *v_other = adj_v[i]; - if (BM_elem_index_get(v_other) != (int)index) { - sculpt_vertex_neighbor_add(iter, BM_elem_index_get(v_other)); + if (v_other != v) { + sculpt_vertex_neighbor_add( + iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other)); } } } } static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, - int index, + PBVHVertRef vertex, SculptVertexNeighborIter *iter) { - MeshElemMap *vert_map = &ss->pmap[index]; + MeshElemMap *vert_map = &ss->pmap[vertex.i]; iter->size = 0; iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; - for (int i = 0; i < ss->pmap[index].count; i++) { + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] < 0) { /* Skip connectivity from hidden faces. */ continue; } const MPoly *p = &ss->mpoly[vert_map->indices[i]]; uint f_adj_v[2]; - if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) { + if (poly_get_adj_loops_from_vert(p, ss->mloop, vertex.i, f_adj_v) != -1) { for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { - if (f_adj_v[j] != index) { - sculpt_vertex_neighbor_add(iter, f_adj_v[j]); + if (f_adj_v[j] != vertex.i) { + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]); } } } @@ -790,14 +807,17 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, if (ss->fake_neighbors.use_fake_neighbors) { BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); - if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { - sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { + sculpt_vertex_neighbor_add( + iter, + BKE_pbvh_make_vref(ss->fake_neighbors.fake_neighbor_index[vertex.i]), + ss->fake_neighbors.fake_neighbor_index[vertex.i]); } } } static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, - const int index, + const PBVHVertRef vertex, const bool include_duplicates, SculptVertexNeighborIter *iter) { @@ -805,8 +825,8 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, * maybe provide coordinate and mask pointers directly rather than converting * back and forth between #CCGElem and global index. */ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, @@ -819,17 +839,20 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, iter->num_duplicates = neighbors.num_duplicates; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; for (int i = 0; i < neighbors.size; i++) { - sculpt_vertex_neighbor_add(iter, - neighbors.coords[i].grid_index * key->grid_area + - neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); + int v = neighbors.coords[i].grid_index * key->grid_area + + neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x; + + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v); } if (ss->fake_neighbors.use_fake_neighbors) { BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); - if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { - sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { + int v = ss->fake_neighbors.fake_neighbor_index[vertex.i]; + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v); } } @@ -839,19 +862,19 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, } void SCULPT_vertex_neighbors_get(SculptSession *ss, - const int index, + const PBVHVertRef vertex, const bool include_duplicates, SculptVertexNeighborIter *iter) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - sculpt_vertex_neighbors_get_faces(ss, index, iter); + sculpt_vertex_neighbors_get_faces(ss, vertex, iter); return; case PBVH_BMESH: - sculpt_vertex_neighbors_get_bmesh(ss, index, iter); + sculpt_vertex_neighbors_get_bmesh(vertex, iter); return; case PBVH_GRIDS: - sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter); + sculpt_vertex_neighbors_get_grids(ss, vertex, include_duplicates, iter); return; } } @@ -862,24 +885,24 @@ static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, c return BLI_BITMAP_TEST(ss->vertex_info.boundary, index); } -bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index) +bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) { + if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) { return true; } - return sculpt_check_boundary_vertex_in_base_mesh(ss, index); + return sculpt_check_boundary_vertex_in_base_mesh(ss, vertex.i); } case PBVH_BMESH: { - BMVert *v = BM_vert_at_index(ss->bm, index); + BMVert *v = (BMVert *)vertex.i; return BM_vert_is_boundary(v); } case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; const SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, .y = vertex_index / key->grid_size}; @@ -940,7 +963,7 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], } typedef struct NearestVertexTLSData { - int nearest_vertex_index; + PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; } NearestVertexTLSData; @@ -957,7 +980,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { - nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex = vd.vertex; nvtd->nearest_vertex_distance_squared = distance_squared; } } @@ -970,17 +993,17 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), { NearestVertexTLSData *join = chunk_join; NearestVertexTLSData *nvtd = chunk; - if (join->nearest_vertex_index == -1) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + if (join->nearest_vertex.i == PBVH_REF_NONE) { + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } -int SCULPT_nearest_vertex_get( +PBVHVertRef SCULPT_nearest_vertex_get( Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original) { SculptSession *ss = ob->sculpt; @@ -995,7 +1018,7 @@ int SCULPT_nearest_vertex_get( }; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { - return -1; + return BKE_pbvh_make_vref(PBVH_REF_NONE); } SculptThreadedTaskData task_data = { @@ -1007,7 +1030,7 @@ int SCULPT_nearest_vertex_get( copy_v3_v3(task_data.nearest_vertex_search_co, co); NearestVertexTLSData nvtd; - nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex.i = PBVH_REF_NONE; nvtd.nearest_vertex_distance_squared = FLT_MAX; TaskParallelSettings settings; @@ -1019,7 +1042,7 @@ int SCULPT_nearest_vertex_get( MEM_SAFE_FREE(nodes); - return nvtd.nearest_vertex_index; + return nvtd.nearest_vertex; } bool SCULPT_is_symmetry_iteration_valid(char i, char symm) @@ -1074,23 +1097,27 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood) int vertex_count = SCULPT_vertex_count_get(ss); SCULPT_vertex_random_access_ensure(ss); - flood->queue = BLI_gsqueue_new(sizeof(int)); + flood->queue = BLI_gsqueue_new(sizeof(intptr_t)); flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices"); } -void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index) +void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex) { - BLI_gsqueue_push(flood->queue, &index); + BLI_gsqueue_push(flood->queue, &vertex); } -void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index) +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex) { - BLI_gsqueue_push(flood->queue, &index); - BLI_BITMAP_ENABLE(flood->visited_vertices, index); + BLI_gsqueue_push(flood->queue, &vertex); + BLI_BITMAP_ENABLE(flood->visited_vertices, vertex.i); } -void SCULPT_floodfill_add_initial_with_symmetry( - Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius) +void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd, + Object *ob, + SculptSession *ss, + SculptFloodFill *flood, + PBVHVertRef vertex, + float radius) { /* Add active vertex and symmetric vertices to the queue. */ const char symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -1098,18 +1125,19 @@ void SCULPT_floodfill_add_initial_with_symmetry( if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { continue; } - int v = -1; + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { - v = index; + v = vertex; } else if (radius > 0.0f) { float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius; float location[3]; - flip_v3_v3(location, SCULPT_vertex_co_get(ss, index), i); + flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false); } - if (v != -1) { + if (v.i != PBVH_REF_NONE) { SCULPT_floodfill_add_initial(flood, v); } } @@ -1124,7 +1152,9 @@ void SCULPT_floodfill_add_active( if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { continue; } - int v = -1; + + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { v = SCULPT_active_vertex_get(ss); } @@ -1134,26 +1164,31 @@ void SCULPT_floodfill_add_active( v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false); } - if (v != -1) { + if (v.i != PBVH_REF_NONE) { SCULPT_floodfill_add_initial(flood, v); } } } -void SCULPT_floodfill_execute( - SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), - void *userdata) +void SCULPT_floodfill_execute(SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool is_duplicate, + void *userdata), + void *userdata) { while (!BLI_gsqueue_is_empty(flood->queue)) { - int from_v; + PBVHVertRef from_v; + BLI_gsqueue_pop(flood->queue, &from_v); SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - const int to_v = ni.index; + const PBVHVertRef to_v = ni.vertex; + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); - if (BLI_BITMAP_TEST(flood->visited_vertices, to_v)) { + if (BLI_BITMAP_TEST(flood->visited_vertices, to_v_i)) { continue; } @@ -1161,7 +1196,7 @@ void SCULPT_floodfill_execute( continue; } - BLI_BITMAP_ENABLE(flood->visited_vertices, to_v); + BLI_BITMAP_ENABLE(flood->visited_vertices, BKE_pbvh_vertex_to_index(ss->pbvh, to_v)); if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { BLI_gsqueue_push(flood->queue, &to_v); @@ -1408,14 +1443,14 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, copy_v3_v3(vd.fno, orig_data.no); } if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } else if (orig_data.unode->type == SCULPT_UNDO_MASK) { *vd.mask = orig_data.mask; } else if (orig_data.unode->type == SCULPT_UNDO_COLOR) { - SCULPT_vertex_color_set(ss, vd.index, orig_data.col); + SCULPT_vertex_color_set(ss, vd.vertex, orig_data.col); } } BKE_pbvh_vertex_iter_end; @@ -2359,12 +2394,12 @@ static float brush_strength(const Sculpt *sd, float SCULPT_brush_strength_factor(SculptSession *ss, const Brush *br, const float brush_point[3], - const float len, + float len, const float vno[3], const float fno[3], - const float mask, - const int vertex_index, - const int thread_id) + float mask, + const PBVHVertRef vertex, + int thread_id) { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; @@ -2448,7 +2483,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, avg *= 1.0f - mask; /* Auto-masking. */ - avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex_index); + avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex); return avg; } @@ -2817,7 +2852,7 @@ typedef struct { float depth; bool original; - int active_vertex_index; + PBVHVertRef active_vertex; float *face_normal; int active_face_grid_index; @@ -3037,13 +3072,13 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -4742,7 +4777,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) srd->ray_normal, &srd->isect_precalc, &srd->depth, - &srd->active_vertex_index, + &srd->active_vertex, &srd->active_face_grid_index, srd->face_normal)) { srd->hit = true; @@ -4876,7 +4911,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, } /* Update the active vertex of the SculptSession. */ - ss->active_vertex_index = srd.active_vertex_index; + ss->active_vertex = srd.active_vertex; SCULPT_vertex_random_access_ensure(ss); copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss)); @@ -5661,10 +5696,10 @@ enum { SCULPT_TOPOLOGY_ID_DEFAULT, }; -static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index) +static int SCULPT_vertex_get_connected_component(SculptSession *ss, PBVHVertRef vertex) { if (ss->vertex_info.connected_component) { - return ss->vertex_info.connected_component[index]; + return ss->vertex_info.connected_component[vertex.i]; } return SCULPT_TOPOLOGY_ID_DEFAULT; } @@ -5681,8 +5716,11 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist) ss->fake_neighbors.current_max_distance = max_dist; } -static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b) +static void SCULPT_fake_neighbor_add(SculptSession *ss, PBVHVertRef v_a, PBVHVertRef v_b) { + int v_index_a = BKE_pbvh_vertex_to_index(ss->pbvh, v_a); + int v_index_b = BKE_pbvh_vertex_to_index(ss->pbvh, v_b); + if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) { ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b; ss->fake_neighbors.fake_neighbor_index[v_index_b] = v_index_a; @@ -5695,7 +5733,7 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss) } typedef struct NearestVertexFakeNeighborTLSData { - int nearest_vertex_index; + PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; int current_topology_id; } NearestVertexFakeNeighborTLSData; @@ -5710,13 +5748,13 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index); + int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.vertex); if (vd_topology_id != nvtd->current_topology_id && ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) { float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { - nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex = vd.vertex; nvtd->nearest_vertex_distance_squared = distance_squared; } } @@ -5730,17 +5768,20 @@ static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata), { NearestVertexFakeNeighborTLSData *join = chunk_join; NearestVertexFakeNeighborTLSData *nvtd = chunk; - if (join->nearest_vertex_index == -1) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + if (join->nearest_vertex.i == PBVH_REF_NONE) { + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } -static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance) +static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd, + Object *ob, + const PBVHVertRef vertex, + float max_distance) { SculptSession *ss = ob->sculpt; PBVHNode **nodes = NULL; @@ -5750,12 +5791,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, .sd = sd, .radius_squared = max_distance * max_distance, .original = false, - .center = SCULPT_vertex_co_get(ss, index), + .center = SCULPT_vertex_co_get(ss, vertex), }; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { - return -1; + return BKE_pbvh_make_vref(PBVH_REF_NONE); } SculptThreadedTaskData task_data = { @@ -5765,12 +5806,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, .max_distance_squared = max_distance * max_distance, }; - copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, vertex)); NearestVertexFakeNeighborTLSData nvtd; - nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex.i = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, index); + nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, vertex); TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -5781,19 +5822,26 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, MEM_SAFE_FREE(nodes); - return nvtd.nearest_vertex_index; + return nvtd.nearest_vertex; } typedef struct SculptTopologyIDFloodFillData { int next_id; } SculptTopologyIDFloodFillData; -static bool SCULPT_connected_components_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { SculptTopologyIDFloodFillData *data = userdata; - ss->vertex_info.connected_component[from_v] = data->next_id; - ss->vertex_info.connected_component[to_v] = data->next_id; + + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + + ss->vertex_info.connected_component[from_v_i] = data->next_id; + ss->vertex_info.connected_component[to_v_i] = data->next_id; return true; } @@ -5817,10 +5865,12 @@ void SCULPT_connected_components_ensure(Object *ob) int next_id = 0; for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (ss->vertex_info.connected_component[i] == SCULPT_TOPOLOGY_ID_NONE) { SculptFloodFill flood; SCULPT_floodfill_init(ss, &flood); - SCULPT_floodfill_add_initial(&flood, i); + SCULPT_floodfill_add_initial(&flood, vertex); SculptTopologyIDFloodFillData data; data.next_id = next_id; SCULPT_floodfill_execute(ss, &flood, SCULPT_connected_components_floodfill_cb, &data); @@ -5878,12 +5928,12 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) SCULPT_fake_neighbor_init(ss, max_dist); for (int i = 0; i < totvert; i++) { - const int from_v = i; + const PBVHVertRef from_v = BKE_pbvh_index_to_vertex(ss->pbvh, i); /* This vertex does not have a fake neighbor yet, search one for it. */ - if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) { - const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist); - if (to_v != -1) { + if (ss->fake_neighbors.fake_neighbor_index[i] == FAKE_NEIGHBOR_NONE) { + const PBVHVertRef to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist); + if (to_v.i != PBVH_REF_NONE) { /* Add the fake neighbor if available. */ SCULPT_fake_neighbor_add(ss, from_v, to_v); } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index bb101717c9b..a9fe8cc4b2f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -114,16 +114,21 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush return false; } -float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert) +float SCULPT_automasking_factor_get(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vert) { if (!automasking) { return 1.0f; } + + int index = BKE_pbvh_vertex_to_index(ss->pbvh, vert); + /* If the cache is initialized with valid info, use the cache. This is used when the * automasking information can't be computed in real time per vertex and needs to be * initialized for the whole mesh when the stroke starts. */ if (automasking->factor) { - return automasking->factor[vert]; + return automasking->factor[index]; } if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { @@ -178,13 +183,18 @@ struct AutomaskFloodFillData { char symm; }; -static bool automask_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool automask_floodfill_cb(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); - data->automask_factor[to_v] = 1.0f; - data->automask_factor[from_v] = 1.0f; + data->automask_factor[to_v_i] = 1.0f; + data->automask_factor[from_v_i] = 1.0f; return (!data->use_radius || SCULPT_is_vertex_inside_brush_radius_symm( SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); @@ -243,7 +253,9 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a int tot_vert = SCULPT_vertex_count_get(ss); int active_face_set = SCULPT_active_face_set_get(ss); for (int i : IndexRange(tot_vert)) { - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { automask_factor[i] *= 0.0f; } } @@ -269,15 +281,17 @@ float *SCULPT_boundary_automasking_init(Object *ob, int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor"); for (int i : IndexRange(totvert)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + edge_distance[i] = EDGE_DISTANCE_INF; switch (mode) { case AUTOMASK_INIT_BOUNDARY_EDGES: - if (SCULPT_vertex_is_boundary(ss, i)) { + if (SCULPT_vertex_is_boundary(ss, vertex)) { edge_distance[i] = 0; } break; case AUTOMASK_INIT_BOUNDARY_FACE_SETS: - if (!SCULPT_vertex_has_unique_face_set(ss, i)) { + if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) { edge_distance[i] = 0; } break; @@ -286,11 +300,13 @@ float *SCULPT_boundary_automasking_init(Object *ob, for (int propagation_it : IndexRange(propagation_steps)) { for (int i : IndexRange(totvert)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (edge_distance[i] != EDGE_DISTANCE_INF) { continue; } SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { if (edge_distance[ni.index] == propagation_it) { edge_distance[i] = propagation_it + 1; } diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index 390fcb9648a..8d08c338b93 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -46,32 +46,38 @@ #define BOUNDARY_STEPS_NONE -1 typedef struct BoundaryInitialVertexFloodFillData { - int initial_vertex; + PBVHVertRef initial_vertex; + int initial_vertex_i; int boundary_initial_vertex_steps; - int boundary_initial_vertex; + PBVHVertRef boundary_initial_vertex; + int boundary_initial_vertex_i; int *floodfill_steps; float radius_sq; } BoundaryInitialVertexFloodFillData; static bool boundary_initial_vertex_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { BoundaryInitialVertexFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!SCULPT_vertex_visible_get(ss, to_v)) { return false; } if (!is_duplicate) { - data->floodfill_steps[to_v] = data->floodfill_steps[from_v] + 1; + data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i] + 1; } else { - data->floodfill_steps[to_v] = data->floodfill_steps[from_v]; + data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i]; } if (SCULPT_vertex_is_boundary(ss, to_v)) { - if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) { - data->boundary_initial_vertex_steps = data->floodfill_steps[to_v]; + if (data->floodfill_steps[to_v_i] < data->boundary_initial_vertex_steps) { + data->boundary_initial_vertex_steps = data->floodfill_steps[to_v_i]; + data->boundary_initial_vertex_i = to_v_i; data->boundary_initial_vertex = to_v; } } @@ -83,9 +89,9 @@ static bool boundary_initial_vertex_floodfill_cb( /* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside * the given radius, if it exists. */ -static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, - const int initial_vertex, - const float radius) +static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, + const PBVHVertRef initial_vertex, + const float radius) { if (SCULPT_vertex_is_boundary(ss, initial_vertex)) { @@ -98,7 +104,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, BoundaryInitialVertexFloodFillData fdata = { .initial_vertex = initial_vertex, - .boundary_initial_vertex = BOUNDARY_VERTEX_NONE, + .boundary_initial_vertex = {BOUNDARY_VERTEX_NONE}, .boundary_initial_vertex_steps = INT_MAX, .radius_sq = radius * radius, }; @@ -119,12 +125,14 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, static int BOUNDARY_INDICES_BLOCK_SIZE = 300; static void sculpt_boundary_index_add(SculptBoundary *boundary, + const PBVHVertRef new_vertex, const int new_index, const float distance, GSet *included_vertices) { - boundary->vertices[boundary->num_vertices] = new_index; + boundary->vertices[boundary->num_vertices] = new_vertex; + if (boundary->distance) { boundary->distance[new_index] = distance; } @@ -135,11 +143,13 @@ static void sculpt_boundary_index_add(SculptBoundary *boundary, if (boundary->num_vertices >= boundary->vertices_capacity) { boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE; boundary->vertices = MEM_reallocN_id( - boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices"); + boundary->vertices, boundary->vertices_capacity * sizeof(PBVHVertRef), "boundary indices"); } }; -static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2) +static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, + const PBVHVertRef v1, + const PBVHVertRef v2) { boundary->edges[boundary->num_edges].v1 = v1; @@ -159,7 +169,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int * as well as to check if the initial vertex is valid. */ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, - const int initial_vertex) + const PBVHVertRef initial_vertex) { if (!SCULPT_vertex_visible_get(ss, initial_vertex)) { @@ -170,9 +180,9 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, int boundary_vertex_count = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) { - if (SCULPT_vertex_visible_get(ss, ni.index)) { + if (SCULPT_vertex_visible_get(ss, ni.vertex)) { neighbor_count++; - if (SCULPT_vertex_is_boundary(ss, ni.index)) { + if (SCULPT_vertex_is_boundary(ss, ni.vertex)) { boundary_vertex_count++; } } @@ -202,13 +212,16 @@ typedef struct BoundaryFloodFillData { GSet *included_vertices; EdgeSet *preview_edges; - int last_visited_vertex; + PBVHVertRef last_visited_vertex; } BoundaryFloodFillData; static bool boundary_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + BoundaryFloodFillData *data = userdata; SculptBoundary *boundary = data->boundary; if (!SCULPT_vertex_is_boundary(ss, to_v)) { @@ -217,9 +230,10 @@ static bool boundary_floodfill_cb( const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v), SCULPT_vertex_co_get(ss, to_v)); const float distance_boundary_to_dst = boundary->distance ? - boundary->distance[from_v] + edge_len : + boundary->distance[from_v_i] + edge_len : 0.0f; - sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices); + sculpt_boundary_index_add( + boundary, to_v, to_v_i, distance_boundary_to_dst, data->included_vertices); if (!is_duplicate) { sculpt_boundary_preview_edge_add(boundary, from_v, to_v); } @@ -229,12 +243,13 @@ static bool boundary_floodfill_cb( static void sculpt_boundary_indices_init(SculptSession *ss, SculptBoundary *boundary, const bool init_boundary_distances, - const int initial_boundary_index) + const PBVHVertRef initial_boundary_vertex) { const int totvert = SCULPT_vertex_count_get(ss); boundary->vertices = MEM_malloc_arrayN( - BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices"); + BOUNDARY_INDICES_BLOCK_SIZE, sizeof(PBVHVertRef), "boundary indices"); + if (init_boundary_distances) { boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances"); } @@ -245,16 +260,21 @@ static void sculpt_boundary_indices_init(SculptSession *ss, SculptFloodFill flood; SCULPT_floodfill_init(ss, &flood); - boundary->initial_vertex = initial_boundary_index; + int initial_boundary_index = BKE_pbvh_vertex_to_index(ss->pbvh, initial_boundary_vertex); + + boundary->initial_vertex = initial_boundary_vertex; + boundary->initial_vertex_i = initial_boundary_index; + copy_v3_v3(boundary->initial_vertex_position, SCULPT_vertex_co_get(ss, boundary->initial_vertex)); - sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices); - SCULPT_floodfill_add_initial(&flood, initial_boundary_index); + sculpt_boundary_index_add( + boundary, initial_boundary_vertex, initial_boundary_index, 0.0f, included_vertices); + SCULPT_floodfill_add_initial(&flood, boundary->initial_vertex); BoundaryFloodFillData fdata = { .boundary = boundary, .included_vertices = included_vertices, - .last_visited_vertex = BOUNDARY_VERTEX_NONE, + .last_visited_vertex = {BOUNDARY_VERTEX_NONE}, }; @@ -262,13 +282,13 @@ static void sculpt_boundary_indices_init(SculptSession *ss, SCULPT_floodfill_free(&flood); /* Check if the boundary loops into itself and add the extra preview edge to close the loop. */ - if (fdata.last_visited_vertex != BOUNDARY_VERTEX_NONE && + if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE && sculpt_boundary_is_vertex_in_editable_boundary(ss, fdata.last_visited_vertex)) { SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) { if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) && - sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) { - sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index); + sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.vertex)) { + sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.vertex); boundary->forms_loop = true; } } @@ -286,7 +306,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss, */ static void sculpt_boundary_edit_data_init(SculptSession *ss, SculptBoundary *boundary, - const int initial_vertex, + const PBVHVertRef initial_vertex, const float radius) { const int totvert = SCULPT_vertex_count_get(ss); @@ -297,19 +317,22 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info"); for (int i = 0; i < totvert; i++) { - boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE; + boundary->edit_info[i].original_vertex_i = BOUNDARY_VERTEX_NONE; boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE; } - GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int)); - GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int)); + GSQueue *current_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef)); + GSQueue *next_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef)); /* Initialized the first iteration with the vertices already in the boundary. This is propagation * step 0. */ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); for (int i = 0; i < boundary->num_vertices; i++) { - boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i]; - boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0; + int index = BKE_pbvh_vertex_to_index(ss->pbvh, boundary->vertices[i]); + + boundary->edit_info[index].original_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, + boundary->vertices[i]); + boundary->edit_info[index].num_propagation_steps = 0; /* This ensures that all duplicate vertices in the boundary have the same original_vertex * index, so the deformation for them will be the same. */ @@ -317,7 +340,8 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, SculptVertexNeighborIter ni_duplis; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) { if (ni_duplis.is_duplicate) { - boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i]; + boundary->edit_info[ni_duplis.index].original_vertex_i = BKE_pbvh_vertex_to_index( + ss->pbvh, boundary->vertices[i]); } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis); @@ -338,31 +362,33 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, } while (!BLI_gsqueue_is_empty(current_iteration)) { - int from_v; + PBVHVertRef from_v; BLI_gsqueue_pop(current_iteration, &from_v); + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index); + const bool is_visible = SCULPT_vertex_visible_get(ss, ni.vertex); if (!is_visible || boundary->edit_info[ni.index].num_propagation_steps != BOUNDARY_STEPS_NONE) { continue; } - boundary->edit_info[ni.index].original_vertex = - boundary->edit_info[from_v].original_vertex; + boundary->edit_info[ni.index].original_vertex_i = + boundary->edit_info[from_v_i].original_vertex_i; BLI_BITMAP_ENABLE(visited_vertices, ni.index); if (ni.is_duplicate) { /* Grids duplicates handling. */ boundary->edit_info[ni.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps; + boundary->edit_info[from_v_i].num_propagation_steps; } else { boundary->edit_info[ni.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps + 1; + boundary->edit_info[from_v_i].num_propagation_steps + 1; - BLI_gsqueue_push(next_iteration, &ni.index); + BLI_gsqueue_push(next_iteration, &ni.vertex); /* When copying the data to the neighbor for the next iteration, it has to be copied to * all its duplicates too. This is because it is not possible to know if the updated @@ -370,12 +396,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, * copy the data in the from_v neighbor iterator. */ if (has_duplicates) { SculptVertexNeighborIter ni_duplis; - SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) { + SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.vertex, ni_duplis) { if (ni_duplis.is_duplicate) { - boundary->edit_info[ni_duplis.index].original_vertex = - boundary->edit_info[from_v].original_vertex; + boundary->edit_info[ni_duplis.index].original_vertex_i = + boundary->edit_info[from_v_i].original_vertex_i; boundary->edit_info[ni_duplis.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps + 1; + boundary->edit_info[from_v_i].num_propagation_steps + 1; } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis); @@ -383,11 +409,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, /* Check the distance using the vertex that was propagated from the initial vertex that * was used to initialize the boundary. */ - if (boundary->edit_info[from_v].original_vertex == initial_vertex) { - boundary->pivot_vertex = ni.index; - copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index)); + if (boundary->edit_info[from_v_i].original_vertex_i == + BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex)) { + boundary->pivot_vertex = ni.vertex; + copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.vertex)); accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v), - SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_vertex_co_get(ss, ni.vertex)); } } } @@ -427,7 +454,8 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps); } - if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) { + if (boundary->edit_info[i].original_vertex_i == + BKE_pbvh_vertex_to_index(ss->pbvh, boundary->initial_vertex)) { /* All vertices that are propagated from the original vertex won't be affected by the * boundary falloff, so there is no need to calculate anything else. */ continue; @@ -439,7 +467,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, continue; } - const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex]; + const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex_i]; float falloff_distance = 0.0f; float direction = 1.0f; @@ -473,22 +501,22 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, SculptBoundary *SCULPT_boundary_data_init(Object *object, Brush *brush, - const int initial_vertex, + const PBVHVertRef initial_vertex, const float radius) { SculptSession *ss = object->sculpt; - if (initial_vertex == BOUNDARY_VERTEX_NONE) { + if (initial_vertex.i == PBVH_REF_NONE) { return NULL; } SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_info_ensure(object); - const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex( + const PBVHVertRef boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex( ss, initial_vertex, radius); - if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) { + if (boundary_initial_vertex.i == BOUNDARY_VERTEX_NONE) { return NULL; } @@ -539,17 +567,22 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { continue; } + + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float dir[3]; float normal[3]; - SCULPT_vertex_normal_get(ss, i, normal); - sub_v3_v3v3(dir, - SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), - SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_normal_get(ss, vertex, normal); + sub_v3_v3v3( + dir, + SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)), + SCULPT_vertex_co_get(ss, vertex)); cross_v3_v3v3( - boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal); - normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]); - copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex], - SCULPT_vertex_co_get(ss, i)); + boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i], dir, normal); + normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]); + copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i], + SCULPT_vertex_co_get(ss, vertex)); } for (int i = 0; i < totvert; i++) { @@ -557,9 +590,9 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo continue; } copy_v3_v3(boundary->bend.pivot_positions[i], - boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]); + boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i]); copy_v3_v3(boundary->bend.pivot_rotation_axis[i], - boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]); + boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]); } } @@ -572,10 +605,12 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { continue; } - sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex], - SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), - SCULPT_vertex_co_get(ss, i)); - normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]); + sub_v3_v3v3( + boundary->slide.directions[boundary->edit_info[i].original_vertex_i], + SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)), + SCULPT_vertex_co_get(ss, BKE_pbvh_index_to_vertex(ss->pbvh, i))); + normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex_i]); } for (int i = 0; i < totvert; i++) { @@ -583,7 +618,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b continue; } copy_v3_v3(boundary->slide.directions[i], - boundary->slide.directions[boundary->edit_info[i].original_vertex]); + boundary->slide.directions[boundary->edit_info[i].original_vertex_i]); } } @@ -660,7 +695,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]); @@ -671,7 +706,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -708,7 +743,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -717,7 +752,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, strength); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -754,7 +789,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -763,7 +798,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, strength); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -798,7 +833,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -806,7 +841,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, boundary->edit_info[vd.index].strength_factor * mask * automask * strength); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -849,7 +884,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position); @@ -860,7 +895,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, add_v3_v3(target_co, boundary->twist.pivot_position); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -898,9 +933,9 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, int total_neighbors = 0; const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) { - add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.vertex)); total_neighbors++; } } @@ -919,7 +954,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, target_co, vd.co, disp, boundary->edit_info[vd.index].strength_factor * mask * strength); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -933,7 +968,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn const int symm_area = ss->cache->mirror_symmetry_pass; if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - int initial_vertex; + PBVHVertRef initial_vertex; + if (ss->cache->mirror_symmetry_pass == 0) { initial_vertex = SCULPT_active_vertex_get(ss); } diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index c607dd02a77..245cbe0f54e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -314,13 +314,13 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -412,13 +412,13 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -510,13 +510,13 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -628,13 +628,13 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -783,13 +783,13 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } } @@ -940,13 +940,13 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1066,13 +1066,13 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1219,7 +1219,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); } @@ -1267,12 +1267,12 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, if (vd.mask) { mul_v3_fl(disp, 1.0f - *vd.mask); } - mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); copy_v3_v3(proxy[vd.i], disp); } if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1352,13 +1352,13 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1426,7 +1426,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); @@ -1436,7 +1436,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, sub_v3_v3(proxy[vd.i], orig_data.co); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1497,7 +1497,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); const int vi = vd.index; @@ -1533,9 +1533,10 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, float normal[3]; if (use_persistent_base) { - SCULPT_vertex_persistent_normal_get(ss, vi, normal); + SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal); mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); + madd_v3_v3v3fl( + final_co, SCULPT_vertex_persistent_co_get(ss, vd.vertex), normal, *disp_factor); } else { copy_v3_v3(normal, orig_data.no); @@ -1551,7 +1552,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, final_co); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1609,7 +1610,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float val[3]; @@ -1624,7 +1625,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1677,13 +1678,13 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1756,7 +1757,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float val1[3]; float val2[3]; @@ -1777,7 +1778,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, add_v3_v3v3(proxy[vd.i], val1, val2); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1872,7 +1873,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp_center[3]; float x_disp[3]; @@ -1896,7 +1897,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], disp_center, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1988,7 +1989,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (grab_silhouette) { @@ -2005,7 +2006,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], grab_delta, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2108,12 +2109,12 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, mul_v3_fl(final_disp, 1.0f - *vd.mask); } - mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); copy_v3_v3(proxy[vd.i], final_disp); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2185,13 +2186,13 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2268,7 +2269,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; float current_disp_norm[3]; @@ -2290,10 +2291,10 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vertex_disp[3]; float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co); normalize_v3_v3(vertex_disp_norm, vertex_disp); if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); @@ -2304,7 +2305,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], final_disp, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2323,31 +2324,31 @@ void SCULPT_relax_vertex(SculptSession *ss, int neighbor_count = 0; zero_v3(smooth_pos); zero_v3(boundary_normal); - const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) { neighbor_count++; if (!filter_boundary_face_sets || - (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { + (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.vertex))) { /* When the vertex to relax is boundary, use only connected boundary vertices for the average * position. */ if (is_boundary) { - if (!SCULPT_vertex_is_boundary(ss, ni.index)) { + if (!SCULPT_vertex_is_boundary(ss, ni.vertex)) { continue; } - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex)); avg_count++; /* Calculate a normal for the constraint plane using the edges of the boundary. */ float to_neighbor[3]; - sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); + sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.vertex), vd->co); normalize_v3(to_neighbor); add_v3_v3(boundary_normal, to_neighbor); } else { - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex)); avg_count++; } } @@ -2376,7 +2377,7 @@ void SCULPT_relax_vertex(SculptSession *ss, normalize_v3_v3(vno, boundary_normal); } else { - SCULPT_vertex_normal_get(ss, vd->index, vno); + SCULPT_vertex_normal_get(ss, vd->vertex, vno); } if (is_zero_v3(vno)) { @@ -2425,12 +2426,12 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2501,17 +2502,17 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float limit_co[3]; float disp[3]; - SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + SCULPT_vertex_limit_surface_get(ss, vd.vertex, limit_co); sub_v3_v3v3(disp, limit_co, vd.co); mul_v3_v3fl(proxy[vd.i], disp, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2567,7 +2568,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; @@ -2594,11 +2595,11 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, float weights_accum = 1.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vertex_disp[3]; float vertex_disp_norm[3]; float neighbor_limit_co[3]; - SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); + SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co); sub_v3_v3v3(vertex_disp, ss->cache->limit_surface_co[ni.index], ss->cache->limit_surface_co[vd.index]); @@ -2623,7 +2624,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, interp_v3_v3v3(vd.co, vd.co, new_co, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2638,7 +2639,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex( PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sub_v3_v3v3(ss->cache->prev_displacement[vd.index], - SCULPT_vertex_co_get(ss, vd.index), + SCULPT_vertex_co_get(ss, vd.vertex), ss->cache->limit_surface_co[vd.index]); } BKE_pbvh_vertex_iter_end; @@ -2657,9 +2658,11 @@ void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes totvert, sizeof(float[3]), "prev displacement"); ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vertex, ss->cache->limit_surface_co[i]); sub_v3_v3v3(ss->cache->prev_displacement[i], - SCULPT_vertex_co_get(ss, i), + SCULPT_vertex_co_get(ss, vertex), ss->cache->limit_surface_co[i]); } } @@ -2722,7 +2725,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.vertex, thread_id) * ss->cache->pressure; float avg[3], val[3]; @@ -2736,7 +2739,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, val); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2799,7 +2802,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, } const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id); if (bstrength > 0.0f) { (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index e29b2172ea7..b4b2c4e48c8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -220,13 +220,16 @@ static void cloth_brush_add_length_constraint(SculptSession *ss, length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL; + PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1); + PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2); + if (use_persistent) { - length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1), - SCULPT_vertex_persistent_co_get(ss, v2)); + length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, vertex1), + SCULPT_vertex_persistent_co_get(ss, vertex2)); } else { - length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1), - SCULPT_vertex_co_get(ss, v2)); + length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, vertex1), + SCULPT_vertex_co_get(ss, vertex2)); } length_constraint->strength = 1.0f; @@ -370,7 +373,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( int tot_indices = 0; build_indices[tot_indices] = vd.index; tot_indices++; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { build_indices[tot_indices] = ni.index; tot_indices++; } @@ -540,7 +543,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float brush_disp[3]; @@ -784,7 +787,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor); const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) * - SCULPT_automasking_factor_get(automasking, ss, vd.index); + SCULPT_automasking_factor_get(automasking, ss, vd.vertex); madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v); madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v); @@ -802,7 +805,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( copy_v3_v3(vd.co, cloth_sim->pos[vd.index]); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -852,10 +855,13 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f); - const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) * - SCULPT_automasking_factor_get(automasking, ss, v1); - const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) * - SCULPT_automasking_factor_get(automasking, ss, v2); + PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1); + PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2); + + const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) * + SCULPT_automasking_factor_get(automasking, ss, vertex1); + const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) * + SCULPT_automasking_factor_get(automasking, ss, vertex2); float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); @@ -1129,15 +1135,17 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation const bool has_deformation_pos = cloth_sim->deformation_pos != NULL; const bool has_softbody_pos = cloth_sim->softbody_pos != NULL; for (int i = 0; i < totverts; i++) { - copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i)); - copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i)); - copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex)); + copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex)); + copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex)); if (has_deformation_pos) { - copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i)); + copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex)); cloth_sim->deformation_strength[i] = 1.0f; } if (has_softbody_pos) { - copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i)); + copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, vertex)); } } } @@ -1146,7 +1154,9 @@ void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSim { const int totverts = SCULPT_vertex_count_get(ss); for (int i = 0; i < totverts; i++) { - copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex)); } } @@ -1427,13 +1437,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float fade = vd.mask ? *vd.mask : 0.0f; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); fade = 1.0f - fade; float force[3] = {0.0f, 0.0f, 0.0f}; float disp[3], temp[3], transform[3][3]; if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) { - if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) { + if (!SCULPT_vertex_has_face_set(ss, vd.vertex, ss->filter_cache->active_face_set)) { continue; } } @@ -1452,7 +1462,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, break; case CLOTH_FILTER_INFLATE: { float normal[3]; - SCULPT_vertex_normal_get(ss, vd.index, normal); + SCULPT_vertex_normal_get(ss, vd.vertex, normal); mul_v3_v3fl(force, normal, fade * data->filter_strength); } break; case CLOTH_FILTER_EXPAND: @@ -1517,7 +1527,9 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent const int totverts = SCULPT_vertex_count_get(ss); for (int i = 0; i < totverts; i++) { - copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex)); } SculptThreadedTaskData data = { diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 00503087e39..ebbb0fa429e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -174,13 +174,13 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2]) BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); /* Average the edge length of the connected edges to the active vertex. */ - int active_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); const float *active_vertex_co = SCULPT_active_vertex_co_get(ss); float edge_length = 0.0f; int tot = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { - edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index)); + edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.vertex)); tot += 1; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -578,14 +578,14 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob, DyntopoDetailSizeEditCustomData *cd) { SculptSession *ss = ob->sculpt; - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); float len_accum = 0; int num_neighbors = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), - SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_vertex_co_get(ss, ni.vertex)); num_neighbors++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 4f884420401..4f91d2215fb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -92,13 +92,16 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss) { int cd_node_layer_index; - char layer_id[] = "_dyntopo_node_id"; + char node_vertex_id[] = "_dyntopo_vnode_id"; + char node_face_id[] = "_dyntopo_fnode_id"; + + cd_node_layer_index = CustomData_get_named_layer_index( + &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); - cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id); if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id); + BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->vdata, CD_PROP_INT32, layer_id); + &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); } ss->cd_vert_node_offset = CustomData_get_n_offset( @@ -108,11 +111,12 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss) ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; - cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT32, layer_id); + cd_node_layer_index = CustomData_get_named_layer_index( + &ss->bm->pdata, CD_PROP_INT32, node_face_id); if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id); + BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, node_face_id); cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->pdata, CD_PROP_INT32, layer_id); + &ss->bm->pdata, CD_PROP_INT32, node_face_id); } ss->cd_face_node_offset = CustomData_get_n_offset( diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index da2c346cf82..dd1c7a36c16 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -140,10 +140,12 @@ enum { */ static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { + int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v); + for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { - if (ss->vertex_info.connected_component[v] == expand_cache->active_connected_components[i]) { + if (ss->vertex_info.connected_component[v_i] == expand_cache->active_connected_components[i]) { return true; } } @@ -158,7 +160,7 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, const int f) { const MLoop *loop = &ss->mloop[ss->mpoly[f].loopstart]; - return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v); + return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_make_vref(loop->v)); } /** @@ -167,14 +169,16 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, */ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { + int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v); + if (expand_cache->texture_distortion_strength == 0.0f) { - return expand_cache->vert_falloff[v]; + return expand_cache->vert_falloff[v_i]; } if (!expand_cache->brush->mtex.tex) { - return expand_cache->vert_falloff[v]; + return expand_cache->vert_falloff[v_i]; } float rgba[4]; @@ -184,7 +188,7 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff; - return expand_cache->vert_falloff[v] + distortion; + return expand_cache->vert_falloff[v_i] + distortion; } /** @@ -209,7 +213,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache) * Main function to get the state of a vertex for the current state and settings of a #ExpandCache. * Returns true when the target data should be modified by expand. */ -static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v) +static bool sculpt_expand_state_get(SculptSession *ss, + ExpandCache *expand_cache, + const PBVHVertRef v) { if (!SCULPT_vertex_visible_get(ss, v)) { return false; @@ -303,7 +309,7 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_ */ static float sculpt_expand_gradient_value_get(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { if (!expand_cache->falloff_gradient) { return 1.0f; @@ -347,7 +353,8 @@ static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCa const int totvert = SCULPT_vertex_count_get(ss); BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); for (int i = 0; i < totvert; i++) { - const bool enabled = sculpt_expand_state_get(ss, expand_cache, i); + const bool enabled = sculpt_expand_state_get( + ss, expand_cache, BKE_pbvh_index_to_vertex(ss->pbvh, i)); BLI_BITMAP_SET(enabled_vertices, i, enabled); } return enabled_vertices; @@ -369,16 +376,18 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss, continue; } + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + bool is_expand_boundary = false; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { if (!BLI_BITMAP_TEST(enabled_vertices, ni.index)) { is_expand_boundary = true; } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, i)) { + if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, vertex)) { is_expand_boundary = true; } @@ -394,12 +403,12 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss, * Utility function to get the closet vertex after flipping an original vertex position based on * an symmetry pass iteration index. */ -static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob, - const char symm_it, - const int original_vertex) +static PBVHVertRef sculpt_expand_get_vertex_index_for_symmetry_pass( + Object *ob, const char symm_it, const PBVHVertRef original_vertex) { SculptSession *ss = ob->sculpt; - int symm_vertex = SCULPT_EXPAND_VERTEX_NONE; + PBVHVertRef symm_vertex = {SCULPT_EXPAND_VERTEX_NONE}; + if (symm_it == 0) { symm_vertex = original_vertex; } @@ -415,7 +424,7 @@ static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob, * Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking * symmetry into account. */ -static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int v) +static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v) { return SCULPT_geodesic_from_vertex_and_symm(sd, ob, v, FLT_MAX); } @@ -432,20 +441,23 @@ typedef struct ExpandFloodFillData { } ExpandFloodFillData; static bool expand_topology_floodfill_cb( - SculptSession *UNUSED(ss), int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + ExpandFloodFillData *data = userdata; if (!is_duplicate) { - const float to_it = data->dists[from_v] + 1.0f; - data->dists[to_v] = to_it; + const float to_it = data->dists[from_v_i] + 1.0f; + data->dists[to_v_i] = to_it; } else { - data->dists[to_v] = data->dists[from_v]; + data->dists[to_v_i] = data->dists[from_v_i]; } return true; } -static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int v) +static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -470,23 +482,26 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons * This creates falloff patterns that follow and snap to the hard edges of the object. */ static bool mask_expand_normal_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + ExpandFloodFillData *data = userdata; if (!is_duplicate) { float current_normal[3], prev_normal[3]; SCULPT_vertex_normal_get(ss, to_v, current_normal); SCULPT_vertex_normal_get(ss, from_v, prev_normal); - const float from_edge_factor = data->edge_factor[from_v]; - data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor; - data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) * - powf(from_edge_factor, data->edge_sensitivity); - CLAMP(data->dists[to_v], 0.0f, 1.0f); + const float from_edge_factor = data->edge_factor[from_v_i]; + data->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * from_edge_factor; + data->dists[to_v_i] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(data->dists[to_v_i], 0.0f, 1.0f); } else { /* PBVH_GRIDS duplicate handling. */ - data->edge_factor[to_v] = data->edge_factor[from_v]; - data->dists[to_v] = data->dists[from_v]; + data->edge_factor[to_v_i] = data->edge_factor[from_v_i]; + data->dists[to_v_i] = data->dists[from_v_i]; } return true; @@ -494,7 +509,7 @@ static bool mask_expand_normal_floodfill_cb( static float *sculpt_expand_normal_falloff_create(Sculpt *sd, Object *ob, - const int v, + const PBVHVertRef v, const float edge_sensitivity) { SculptSession *ss = ob->sculpt; @@ -520,9 +535,11 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd, for (int repeat = 0; repeat < 2; repeat++) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg = 0.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { avg += dists[ni.index]; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -539,7 +556,7 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd, * Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into * account. */ -static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) +static float *sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -554,11 +571,14 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); - if (symm_vertex != -1) { + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); + if (symm_vertex.i != SCULPT_EXPAND_VERTEX_NONE) { const float *co = SCULPT_vertex_co_get(ss, symm_vertex); for (int i = 0; i < totvert; i++) { - dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i))); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, vertex))); } } } @@ -571,13 +591,13 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) * boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it * stays parallel to the boundary, increasing the falloff value by 1 on each step. */ -static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const int v) +static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "spherical dist"); BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); - GSQueue *queue = BLI_gsqueue_new(sizeof(int)); + GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef)); /* Search and initialize a boundary per symmetry pass, then mark those vertices as visited. */ const char symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -586,7 +606,8 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, symm_vertex, FLT_MAX); if (!boundary) { @@ -595,7 +616,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i for (int i = 0; i < boundary->num_vertices; i++) { BLI_gsqueue_push(queue, &boundary->vertices[i]); - BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices[i]); + BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices_i[i]); } SCULPT_boundary_data_free(boundary); } @@ -607,17 +628,19 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i /* Propagate the values from the boundaries to the rest of the mesh. */ while (!BLI_gsqueue_is_empty(queue)) { - int v_next; + PBVHVertRef v_next; + BLI_gsqueue_pop(queue, &v_next); + int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next); SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_next, ni) { if (BLI_BITMAP_TEST(visited_vertices, ni.index)) { continue; } - dists[ni.index] = dists[v_next] + 1.0f; + dists[ni.index] = dists[v_next_i] + 1.0f; BLI_BITMAP_ENABLE(visited_vertices, ni.index); - BLI_gsqueue_push(queue, &ni.index); + BLI_gsqueue_push(queue, &ni.vertex); } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); } @@ -632,7 +655,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i * the base mesh faces when checking a vertex neighbor. For this reason, this is not implement * using the general flood-fill and sculpt neighbors accessors. */ -static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) +static float *sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -647,17 +670,19 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) /* Search and mask as visited the initial vertices using the enabled symmetry passes. */ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); - GSQueue *queue = BLI_gsqueue_new(sizeof(int)); + GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef)); const char symm = SCULPT_mesh_symmetry_xyz_get(ob); for (char symm_it = 0; symm_it <= symm; symm_it++) { if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); + int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex); BLI_gsqueue_push(queue, &symm_vertex); - BLI_BITMAP_ENABLE(visited_vertices, symm_vertex); + BLI_BITMAP_ENABLE(visited_vertices, symm_vertex_i); } if (BLI_gsqueue_is_empty(queue)) { @@ -667,17 +692,20 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) /* Propagate the falloff increasing the value by 1 each time a new vertex is visited. */ Mesh *mesh = ob->data; while (!BLI_gsqueue_is_empty(queue)) { - int v_next; + PBVHVertRef v_next; BLI_gsqueue_pop(queue, &v_next); - for (int j = 0; j < ss->pmap[v_next].count; j++) { - MPoly *p = &ss->mpoly[ss->pmap[v_next].indices[j]]; + + int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next); + + for (int j = 0; j < ss->pmap[v_next_i].count; j++) { + MPoly *p = &ss->mpoly[ss->pmap[v_next_i].indices[j]]; for (int l = 0; l < p->totloop; l++) { - const int neighbor_v = mesh->mloop[p->loopstart + l].v; - if (BLI_BITMAP_TEST(visited_vertices, neighbor_v)) { + const PBVHVertRef neighbor_v = BKE_pbvh_make_vref(mesh->mloop[p->loopstart + l].v); + if (BLI_BITMAP_TEST(visited_vertices, neighbor_v.i)) { continue; } - dists[neighbor_v] = dists[v_next] + 1.0f; - BLI_BITMAP_ENABLE(visited_vertices, neighbor_v); + dists[neighbor_v.i] = dists[v_next_i] + 1.0f; + BLI_BITMAP_ENABLE(visited_vertices, neighbor_v.i); BLI_gsqueue_push(queue, &neighbor_v); } } @@ -701,11 +729,13 @@ static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss, const int totvert = SCULPT_vertex_count_get(ss); expand_cache->max_vert_falloff = -FLT_MAX; for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (expand_cache->vert_falloff[i] == FLT_MAX) { continue; } - if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) { continue; } @@ -856,7 +886,9 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob, if (!BLI_BITMAP_TEST(boundary_vertices, i)) { continue; } - SCULPT_floodfill_add_and_skip_initial(&flood, i); + + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + SCULPT_floodfill_add_and_skip_initial(&flood, vertex); } MEM_freeN(boundary_vertices); @@ -921,10 +953,12 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); for (int i = 0; i < totvert; i++) { - if (!SCULPT_vertex_has_unique_face_set(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) { continue; } - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { continue; } BLI_BITMAP_ENABLE(enabled_vertices, i); @@ -941,8 +975,10 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, if (internal_falloff) { for (int i = 0; i < totvert; i++) { - if (!(SCULPT_vertex_has_face_set(ss, i, active_face_set) && - SCULPT_vertex_has_unique_face_set(ss, i))) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!(SCULPT_vertex_has_face_set(ss, vertex, active_face_set) && + SCULPT_vertex_has_unique_face_set(ss, vertex))) { continue; } expand_cache->vert_falloff[i] *= -1.0f; @@ -960,7 +996,9 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, } else { for (int i = 0; i < totvert; i++) { - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { continue; } expand_cache->vert_falloff[i] = 0.0f; @@ -976,7 +1014,7 @@ static void sculpt_expand_falloff_factors_from_vertex_and_symm_create( ExpandCache *expand_cache, Sculpt *sd, Object *ob, - const int v, + const PBVHVertRef v, eSculptExpandFalloffType falloff_type) { MEM_SAFE_FREE(expand_cache->vert_falloff); @@ -1128,7 +1166,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp PBVHNode *node = nodes[n]; PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - SCULPT_vertex_color_set(ss, vd.index, expand_cache->original_colors[vd.index]); + SCULPT_vertex_color_set(ss, vd.vertex, expand_cache->original_colors[vd.index]); } BKE_pbvh_vertex_iter_end; BKE_pbvh_node_mark_redraw(node); @@ -1215,12 +1253,12 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { const float initial_mask = *vd.mask; - const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex); float new_mask; if (enabled) { - new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex); } else { new_mask = 0.0f; @@ -1284,13 +1322,13 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { float initial_color[4]; - SCULPT_vertex_color_get(ss, vd.index, initial_color); + SCULPT_vertex_color_get(ss, vd.vertex, initial_color); - const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex); float fade; if (enabled) { - fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex); } else { fade = 0.0f; @@ -1311,7 +1349,7 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, continue; } - SCULPT_vertex_color_set(ss, vd.index, final_color); + SCULPT_vertex_color_set(ss, vd.vertex, final_color); any_changed = true; } @@ -1358,14 +1396,18 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { expand_cache->original_mask = MEM_malloc_arrayN(totvert, sizeof(float), "initial mask"); for (int i = 0; i < totvert; i++) { - expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, vertex); } } if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) { expand_cache->original_colors = MEM_malloc_arrayN(totvert, sizeof(float[4]), "initial colors"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, expand_cache->original_colors[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_color_get(ss, vertex, expand_cache->original_colors[i]); } } } @@ -1388,14 +1430,16 @@ static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expa } } -static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex) +static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const PBVHVertRef vertex) { SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; ExpandCache *expand_cache = ss->expand_cache; + int vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + /* Update the active factor in the cache. */ - if (vertex == SCULPT_EXPAND_VERTEX_NONE) { + if (vertex.i == SCULPT_EXPAND_VERTEX_NONE) { /* This means that the cursor is not over the mesh, so a valid active falloff can't be * determined. In this situations, don't evaluate enabled states and default all vertices in * connected components to enabled. */ @@ -1403,7 +1447,7 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v expand_cache->all_enabled = true; } else { - expand_cache->active_falloff = expand_cache->vert_falloff[vertex]; + expand_cache->active_falloff = expand_cache->vert_falloff[vertex_i]; expand_cache->all_enabled = false; } @@ -1444,14 +1488,16 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v * Updates the #SculptSession cursor data and gets the active vertex * if the cursor is over the mesh. */ -static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2]) +static PBVHVertRef sculpt_expand_target_vertex_update_and_get(bContext *C, + Object *ob, + const float mval[2]) { SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) { return SCULPT_active_vertex_get(ss); } - return SCULPT_EXPAND_VERTEX_NONE; + return BKE_pbvh_make_vref(SCULPT_EXPAND_VERTEX_NONE); } /** @@ -1487,15 +1533,17 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache const float *expand_init_co = SCULPT_vertex_co_get(ss, expand_cache->initial_active_vertex); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (!BLI_BITMAP_TEST(boundary_vertices, i)) { continue; } - if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) { continue; } - const float *vertex_co = SCULPT_vertex_co_get(ss, i); + const float *vertex_co = SCULPT_vertex_co_get(ss, vertex); if (!SCULPT_check_vertex_pivot_symmetry(vertex_co, expand_init_co, symm)) { continue; @@ -1550,9 +1598,8 @@ static void sculpt_expand_finish(bContext *C) * Finds and stores in the #ExpandCache the sculpt connected component index for each symmetry pass * needed for expand. */ -static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, - ExpandCache *expand_cache, - const int initial_vertex) +static void sculpt_expand_find_active_connected_components_from_vert( + Object *ob, ExpandCache *expand_cache, const PBVHVertRef initial_vertex) { SculptSession *ss = ob->sculpt; for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { @@ -1565,11 +1612,13 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( ob, symm_it, initial_vertex); + int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex); + expand_cache->active_connected_components[(int)symm_it] = - ss->vertex_info.connected_component[symm_vertex]; + ss->vertex_info.connected_component[symm_vertex_i]; } } @@ -1583,14 +1632,20 @@ static void sculpt_expand_set_initial_components_for_mouse(bContext *C, const float mval[2]) { SculptSession *ss = ob->sculpt; - int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval); - if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) { + + PBVHVertRef initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval); + + if (initial_vertex.i == SCULPT_EXPAND_VERTEX_NONE) { /* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active * vertex in the sculpt session. */ initial_vertex = SCULPT_active_vertex_get(ss); } + + int initial_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex); + copy_v2_v2(ss->expand_cache->initial_mouse, mval); expand_cache->initial_active_vertex = initial_vertex; + expand_cache->initial_active_vertex_i = initial_vertex_i; expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss); if (expand_cache->next_face_set == SCULPT_FACE_SET_NONE) { @@ -1690,7 +1745,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event /* Update and get the active vertex (and face) from the cursor. */ const float mval_fl[2] = {UNPACK2(event->mval)}; - const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl); + const PBVHVertRef target_expand_vertex = sculpt_expand_target_vertex_update_and_get( + C, ob, mval_fl); /* Handle the modal keymap state changes. */ ExpandCache *expand_cache = ss->expand_cache; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 91763a15e37..f045ba841f3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -142,7 +142,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) { @@ -161,11 +161,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (fade > 0.05f) { - SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set); + SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set); } } } @@ -199,7 +199,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } - if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) { + if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) { continue; } @@ -210,12 +210,12 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -324,8 +324,11 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) if (mode == SCULPT_FACE_SET_MASKED) { for (int i = 0; i < tot_vert; i++) { - if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (SCULPT_vertex_mask_get(ss, vertex) >= threshold && + SCULPT_vertex_visible_get(ss, vertex)) { + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } } @@ -337,7 +340,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) * sets and the performance hit of rendering the overlay. */ bool all_visible = true; for (int i = 0; i < tot_vert; i++) { - if (!SCULPT_vertex_visible_get(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_visible_get(ss, vertex)) { all_visible = false; break; } @@ -351,15 +356,19 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } for (int i = 0; i < tot_vert; i++) { - if (SCULPT_vertex_visible_get(ss, i)) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (SCULPT_vertex_visible_get(ss, vertex)) { + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } } if (mode == SCULPT_FACE_SET_ALL) { for (int i = 0; i < tot_vert; i++) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } @@ -869,7 +878,9 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) * be synced from face sets to non-manifold vertices. */ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { for (int i = 0; i < tot_vert; i++) { - if (!SCULPT_vertex_visible_get(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_visible_get(ss, vertex)) { hidden_vertex = true; break; } @@ -1222,9 +1233,11 @@ static void sculpt_face_set_edit_fair_face_set(Object *ob, SCULPT_boundary_info_ensure(ob); for (int i = 0; i < totvert; i++) { - fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) && - SCULPT_vertex_has_face_set(ss, i, active_face_set_id) && - SCULPT_vertex_has_unique_face_set(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, vertex) && + SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) && + SCULPT_vertex_has_unique_face_set(ss, vertex); } MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index 27092bf9a04..7a1e08ea713 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -104,7 +104,7 @@ static void color_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f) { continue; } @@ -189,10 +189,10 @@ static void color_filter_task_cb(void *__restrict userdata, case COLOR_FILTER_SMOOTH: { fade = clamp_f(fade, -1.0f, 1.0f); float smooth_color[4]; - SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); if (fade < 0.0f) { interp_v4_v4v4(smooth_color, smooth_color, col, 0.5f); @@ -224,7 +224,7 @@ static void color_filter_task_cb(void *__restrict userdata, } } - SCULPT_vertex_color_set(ss, vd.index, final_color); + SCULPT_vertex_color_set(ss, vd.vertex, final_color); } BKE_pbvh_vertex_iter_end; BKE_pbvh_node_mark_update_color(data->nodes[n]); @@ -240,7 +240,8 @@ static void sculpt_color_presmooth_init(SculptSession *ss) } for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, ss->filter_cache->pre_smoothed_color[i]); + SCULPT_vertex_color_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ss->filter_cache->pre_smoothed_color[i]); } for (int iteration = 0; iteration < 2; iteration++) { @@ -249,7 +250,7 @@ static void sculpt_color_presmooth_init(SculptSession *ss) int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ni) { float col[4] = {0}; copy_v4_v4(col, ss->filter_cache->pre_smoothed_color[ni.index]); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index a21656435a3..fa4fe191273 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -103,7 +103,7 @@ static void mask_filter_task_cb(void *__restrict userdata, switch (mode) { case MASK_FILTER_SMOOTH: case MASK_FILTER_SHARPEN: { - float val = SCULPT_neighbor_mask_average(ss, vd.index); + float val = SCULPT_neighbor_mask_average(ss, vd.vertex); val -= *vd.mask; @@ -123,7 +123,7 @@ static void mask_filter_task_cb(void *__restrict userdata, } case MASK_FILTER_GROW: max = 0.0f; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; if (vmask_f > max) { max = vmask_f; @@ -134,7 +134,7 @@ static void mask_filter_task_cb(void *__restrict userdata, break; case MASK_FILTER_SHRINK: min = 1.0f; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; if (vmask_f < min) { min = vmask_f; @@ -214,7 +214,8 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask"); for (int j = 0; j < num_verts; j++) { - prev_mask[j] = SCULPT_vertex_mask_get(ss, j); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, j); + prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex); } } @@ -305,9 +306,9 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd) zero_v3(avg); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) { float normalized[3]; - sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co); + sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co); normalize_v3(normalized); add_v3_v3(avg, normalized); total++; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 9e84d9ac65d..4f45b7917ec 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -296,7 +296,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) { /* Surface Smooth can't skip the loop for this vertex as it needs to calculate its @@ -314,7 +314,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, } if (filter_type == MESH_FILTER_RELAX_FACE_SETS) { - if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) { + if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) { continue; } } @@ -322,7 +322,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, switch (filter_type) { case MESH_FILTER_SMOOTH: fade = clamp_f(fade, -1.0f, 1.0f); - SCULPT_neighbor_coords_average_interior(ss, avg, vd.index); + SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex); sub_v3_v3v3(val, avg, orig_co); madd_v3_v3v3fl(val, orig_co, val, fade); sub_v3_v3v3(disp, val, orig_co); @@ -385,7 +385,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, disp, vd.co, ss->filter_cache->surface_smooth_laplacian_disp, - vd.index, + vd.vertex, orig_data.co, ss->filter_cache->surface_smooth_shape_preservation); break; @@ -399,10 +399,10 @@ static void mesh_filter_task_cb(void *__restrict userdata, float disp_sharpen[3] = {0.0f, 0.0f, 0.0f}; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float disp_n[3]; sub_v3_v3v3( - disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index)); + disp_n, SCULPT_vertex_co_get(ss, ni.vertex), SCULPT_vertex_co_get(ss, vd.vertex)); mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]); add_v3_v3(disp_sharpen, disp_n); } @@ -412,7 +412,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, float disp_avg[3]; float avg_co[3]; - SCULPT_neighbor_coords_average(ss, avg_co, vd.index); + SCULPT_neighbor_coords_average(ss, avg_co, vd.vertex); sub_v3_v3v3(disp_avg, avg_co, vd.co); mul_v3_v3fl( disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index])); @@ -457,7 +457,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, } copy_v3_v3(vd.co, final_pos); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -473,9 +473,11 @@ static void mesh_filter_enhance_details_init_directions(SculptSession *ss) filter_cache->detail_directions = MEM_malloc_arrayN( totvert, sizeof(float[3]), "detail directions"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); } } @@ -500,7 +502,9 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss) filter_cache->limit_surface_co = MEM_malloc_arrayN( totvert, sizeof(float[3]), "limit surface co"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vertex, filter_cache->limit_surface_co[i]); } } @@ -520,9 +524,11 @@ static void mesh_filter_sharpen_init(SculptSession *ss, totvert, sizeof(float[3]), "sharpen detail direction"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]); } @@ -544,12 +550,14 @@ static void mesh_filter_sharpen_init(SculptSession *ss, smooth_iterations < filter_cache->sharpen_curvature_smooth_iterations; smooth_iterations++) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float direction_avg[3] = {0.0f, 0.0f, 0.0f}; float sharpen_avg = 0; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]); sharpen_avg += filter_cache->sharpen_factor[ni.index]; total++; @@ -576,7 +584,7 @@ static void mesh_filter_surface_smooth_displace_task_cb( float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f) { continue; } @@ -584,7 +592,7 @@ static void mesh_filter_surface_smooth_displace_task_cb( SCULPT_surface_smooth_displace_step(ss, vd.co, ss->filter_cache->surface_smooth_laplacian_disp, - vd.index, + vd.vertex, ss->filter_cache->surface_smooth_current_vertex, clamp_f(fade, 0.0f, 1.0f)); } diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c index 1beb5d48961..ecf8c4586ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c @@ -279,9 +279,12 @@ static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices return dists; } - const float *first_affected_co = SCULPT_vertex_co_get(ss, first_affected); + const float *first_affected_co = SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, first_affected)); for (int i = 0; i < totvert; i++) { - dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, vertex)); } return dists; @@ -305,7 +308,7 @@ float *SCULPT_geodesic_distances_create(Object *ob, float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, Object *ob, - const int vertex, + const PBVHVertRef vertex, const float limit_radius) { SculptSession *ss = ob->sculpt; @@ -314,7 +317,8 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, const char symm = SCULPT_mesh_symmetry_xyz_get(ob); for (char i = 0; i <= symm; ++i) { if (SCULPT_is_symmetry_iteration_valid(i, symm)) { - int v = -1; + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { v = vertex; } @@ -323,8 +327,8 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false); } - if (v != -1) { - BLI_gset_add(initial_vertices, POINTER_FROM_INT(v)); + if (v.i != PBVH_REF_NONE) { + BLI_gset_add(initial_vertices, POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ss->pbvh, v))); } } } @@ -334,10 +338,11 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, return dists; } -float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius) +float *SCULPT_geodesic_from_vertex(Object *ob, const PBVHVertRef vertex, const float limit_radius) { GSet *initial_vertices = BLI_gset_int_new("initial_vertices"); - BLI_gset_add(initial_vertices, POINTER_FROM_INT(vertex)); + BLI_gset_add(initial_vertices, + POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ob->sculpt->pbvh, vertex))); float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius); BLI_gset_free(initial_vertices, NULL); return dists; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 166504ca8a9..6a10f7cad18 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -59,10 +59,13 @@ typedef struct SculptCursorGeometryInfo { typedef struct SculptVertexNeighborIter { /* Storage */ - int *neighbors; + PBVHVertRef *neighbors; + int *neighbor_indices; int size; int capacity; - int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; + + PBVHVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; + int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; /* Internal iterator. */ int num_duplicates; @@ -70,6 +73,7 @@ typedef struct SculptVertexNeighborIter { /* Public */ int index; + PBVHVertRef vertex; bool is_duplicate; } SculptVertexNeighborIter; @@ -318,7 +322,7 @@ typedef struct SculptThreadedTaskData { bool mask_by_color_preserve_mask; /* Index of the vertex that is going to be used as a reference for the colors. */ - int mask_by_color_vertex; + PBVHVertRef mask_by_color_vertex; float *mask_by_color_floodfill; int face_set; @@ -691,7 +695,8 @@ typedef struct ExpandCache { * during the execution of Expand by moving the origin. */ float initial_mouse_move[2]; float initial_mouse[2]; - int initial_active_vertex; + PBVHVertRef initial_active_vertex; + int initial_active_vertex_i; int initial_active_face_set; /* Maximum number of vertices allowed in the SculptSession for previewing the falloff using @@ -899,14 +904,14 @@ bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cach void SCULPT_vertex_random_access_ensure(struct SculptSession *ss); int SCULPT_vertex_count_get(struct SculptSession *ss); -const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); +const float *SCULPT_vertex_co_get(struct SculptSession *ss, PBVHVertRef vertex); /** Get the normal for a given sculpt vertex; do not modify the result */ -void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]); +void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]); -float SCULPT_vertex_mask_get(struct SculptSession *ss, int index); -void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]); -void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]); +float SCULPT_vertex_mask_get(struct SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]); +void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]); /** Returns true if a color attribute exists in the current sculpt session. */ bool SCULPT_has_colors(const SculptSession *ss); @@ -914,19 +919,19 @@ bool SCULPT_has_colors(const SculptSession *ss); /** Returns true if the active color attribute is on loop (ATTR_DOMAIN_CORNER) domain. */ bool SCULPT_has_loop_colors(const struct Object *ob); -const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); -void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); +const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]); /** * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */ -const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index); +const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex); /** * Returns the info of the limit surface when multi-res is available, * otherwise it returns the current coordinate of the vertex. */ -void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); +void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3]); /** * Returns the pointer to the coordinates that should be edited from a brush tool iterator @@ -937,7 +942,7 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, PBVHVertexIter *iter); void SCULPT_vertex_neighbors_get(struct SculptSession *ss, - int index, + PBVHVertRef vertex, bool include_duplicates, SculptVertexNeighborIter *iter); @@ -946,7 +951,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; + neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; /** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come * first since they are nearest for floodfill. */ @@ -954,7 +960,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ neighbor_iterator.i--) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ neighbor_iterator.size - neighbor_iterator.num_duplicates); @@ -965,7 +972,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, } \ ((void)0) -int SCULPT_active_vertex_get(SculptSession *ss); +PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss); const float *SCULPT_active_vertex_co_get(SculptSession *ss); void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]); @@ -985,7 +992,7 @@ void SCULPT_fake_neighbors_free(struct Object *ob); /* Vertex Info. */ void SCULPT_boundary_info_ensure(Object *object); /* Boundary Info needs to be initialized in order to use this function. */ -bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index); +bool SCULPT_vertex_is_boundary(const SculptSession *ss, PBVHVertRef vertex); void SCULPT_connected_components_ensure(Object *ob); @@ -995,8 +1002,8 @@ void SCULPT_connected_components_ensure(Object *ob); /** \name Sculpt Visibility API * \{ */ -void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible); -bool SCULPT_vertex_visible_get(SculptSession *ss, int index); +void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible); +bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex); void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob); void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); @@ -1008,17 +1015,17 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); * \{ */ int SCULPT_active_face_set_get(SculptSession *ss); -int SCULPT_vertex_face_set_get(SculptSession *ss, int index); -void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set); +int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set); -bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set); -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index); +bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set); +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex); int SCULPT_face_set_next_available_get(SculptSession *ss); void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible); -bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index); -bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index); +bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex); +bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex); void SCULPT_face_sets_visibility_invert(SculptSession *ss); void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible); @@ -1104,11 +1111,11 @@ void SCULPT_calc_area_normal_and_center( void SCULPT_calc_area_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]); -int SCULPT_nearest_vertex_get(struct Sculpt *sd, - struct Object *ob, - const float co[3], - float max_distance, - bool use_original); +PBVHVertRef SCULPT_nearest_vertex_get(struct Sculpt *sd, + struct Object *ob, + const float co[3], + float max_distance, + bool use_original); int SCULPT_plane_point_side(const float co[3], const float plane[4]); int SCULPT_plane_trim(const struct StrokeCache *cache, @@ -1187,7 +1194,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss, const float vno[3], const float fno[3], float mask, - int vertex_index, + const PBVHVertRef vertex, int thread_id); /** @@ -1218,15 +1225,18 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd, struct Object *ob, struct SculptSession *ss, SculptFloodFill *flood, - int index, + PBVHVertRef vertex, float radius); -void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_execute( - struct SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), - void *userdata); +void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex); +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex); +void SCULPT_floodfill_execute(struct SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool is_duplicate, + void *userdata), + void *userdata); void SCULPT_floodfill_free(SculptFloodFill *flood); /** \} */ @@ -1276,7 +1286,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, SculptSession *ss, - int vert); + PBVHVertRef vertex); /* Returns the automasking cache depending on the active tool. Used for code that can run both for * brushes and filter. */ @@ -1309,9 +1319,9 @@ float *SCULPT_geodesic_distances_create(struct Object *ob, float limit_radius); float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd, struct Object *ob, - int vertex, + PBVHVertRef vertex, float limit_radius); -float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius); +float *SCULPT_geodesic_from_vertex(Object *ob, PBVHVertRef vertex, float limit_radius); /** \} */ /* -------------------------------------------------------------------- */ @@ -1417,14 +1427,16 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) */ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v); -void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index); -float SCULPT_neighbor_mask_average(SculptSession *ss, int index); -void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index); +void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex); +float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex); /** * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking. */ -void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index); +void SCULPT_neighbor_coords_average_interior(SculptSession *ss, + float result[3], + PBVHVertRef vertex); void SCULPT_smooth( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask); @@ -1436,11 +1448,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, float *disp, const float co[3], float (*laplacian_disp)[3], - int v_index, + PBVHVertRef vertex, const float origco[3], float alpha); -void SCULPT_surface_smooth_displace_step( - SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade); +void SCULPT_surface_smooth_displace_step(SculptSession *ss, + float *co, + float (*laplacian_disp)[3], + PBVHVertRef vertex, + float beta, + float fade); void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); /* Slide/Relax */ @@ -1646,7 +1662,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain); */ struct SculptBoundary *SCULPT_boundary_data_init(Object *object, Brush *brush, - int initial_vertex, + PBVHVertRef initial_vertex, float radius); void SCULPT_boundary_data_free(struct SculptBoundary *boundary); /* Main Brush Function. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 03243f00c49..2e661711172 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -97,11 +97,14 @@ static void sculpt_expand_task_cb(void *__restrict userdata, PBVHVertexIter vd; int update_it = data->mask_expand_update_it; + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex); + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { int vi = vd.index; float final_mask = *vd.mask; if (data->mask_expand_use_normals) { - if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] < + if (ss->filter_cache->normal_factor[active_vertex_i] < ss->filter_cache->normal_factor[vd.index]) { final_mask = 1.0f; } @@ -121,7 +124,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata, if (data->mask_expand_create_face_set) { if (final_mask == 1.0f) { - SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set); + SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set); } BKE_pbvh_node_mark_redraw(node); } @@ -164,10 +167,13 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * if (RNA_boolean_get(op->ptr, "use_cursor")) { SculptCursorGeometryInfo sgi; + const float mval_fl[2] = {UNPACK2(event->mval)}; if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss)); + /* The cursor is over the mesh, get the update iteration from the updated active vertex. */ - mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)]; + mask_expand_update_it = ss->filter_cache->mask_update_it[active_vertex_i]; } else { /* When the cursor is outside the mesh, affect the entire connected component. */ @@ -288,13 +294,16 @@ typedef struct MaskExpandFloodFillData { } MaskExpandFloodFillData; static bool mask_expand_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { MaskExpandFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!is_duplicate) { - int to_it = ss->filter_cache->mask_update_it[from_v] + 1; - ss->filter_cache->mask_update_it[to_v] = to_it; + int to_it = ss->filter_cache->mask_update_it[from_v_i] + 1; + ss->filter_cache->mask_update_it[to_v_i] = to_it; if (to_it > ss->filter_cache->mask_update_last_it) { ss->filter_cache->mask_update_last_it = to_it; } @@ -303,20 +312,20 @@ static bool mask_expand_floodfill_cb( float current_normal[3], prev_normal[3]; SCULPT_vertex_normal_get(ss, to_v, current_normal); SCULPT_vertex_normal_get(ss, from_v, prev_normal); - const float from_edge_factor = ss->filter_cache->edge_factor[from_v]; - ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * - from_edge_factor; - ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) * - powf(from_edge_factor, data->edge_sensitivity); - CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f); + const float from_edge_factor = ss->filter_cache->edge_factor[from_v_i]; + ss->filter_cache->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * + from_edge_factor; + ss->filter_cache->normal_factor[to_v_i] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(ss->filter_cache->normal_factor[to_v_i], 0.0f, 1.0f); } } else { /* PBVH_GRIDS duplicate handling. */ - ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v]; + ss->filter_cache->mask_update_it[to_v_i] = ss->filter_cache->mask_update_it[from_v_i]; if (data->use_normals) { - ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v]; - ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v]; + ss->filter_cache->edge_factor[to_v_i] = ss->filter_cache->edge_factor[from_v_i]; + ss->filter_cache->normal_factor[to_v_i] = ss->filter_cache->normal_factor[from_v_i]; } } @@ -389,13 +398,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent else { ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); for (int i = 0; i < vertex_count; i++) { - ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, vertex); } } + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss)); + ss->filter_cache->mask_update_last_it = 1; ss->filter_cache->mask_update_current_it = 1; - ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0; + ss->filter_cache->mask_update_it[active_vertex_i] = 0; copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss)); @@ -414,9 +427,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (use_normals) { for (int repeat = 0; repeat < 2; repeat++) { for (int i = 0; i < vertex_count; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg = 0.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { avg += ss->filter_cache->normal_factor[ni.index]; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c index 025f34ab2d7..cc27623adb0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -99,7 +99,7 @@ static void mask_init_task_cb(void *__restrict userdata, *vd.mask = BLI_hash_int_01(vd.index + seed); break; case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: { - const int face_set = SCULPT_vertex_face_set_get(ss, vd.index); + const int face_set = SCULPT_vertex_face_set_get(ss, vd.vertex); *vd.mask = BLI_hash_int_01(face_set + seed); break; } diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index 50cb75e8089..1e8731e54c0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -86,7 +86,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); /* Sample the normal and area of the +X and -X axis individually. */ @@ -194,13 +194,13 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 8f96f5cddea..151eb7744ea 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -129,8 +129,10 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) "layer persistent base"); for (int i = 0; i < totvert; i++) { - copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); - SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, vertex)); + SCULPT_vertex_normal_get(ss, vertex, ss->persistent_base[i].no); ss->persistent_base[i].disp = 0.0f; } @@ -543,7 +545,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob = CTX_data_active_object(C); - ss->preview_vert_index_count = 0; + ss->preview_vert_count = 0; int totpoints = 0; /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ @@ -573,29 +575,32 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; - if (ss->preview_vert_index_list == NULL) { - ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); + if (ss->preview_vert_list == NULL) { + ss->preview_vert_list = MEM_callocN(max_preview_vertices * sizeof(PBVHVertRef), + "preview lines"); } - GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); - int active_v = SCULPT_active_vertex_get(ss); + GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(PBVHVertRef)); + PBVHVertRef active_v = SCULPT_active_vertex_get(ss); BLI_gsqueue_push(not_visited_vertices, &active_v); while (!BLI_gsqueue_is_empty(not_visited_vertices)) { - int from_v; + PBVHVertRef from_v; + BLI_gsqueue_pop(not_visited_vertices, &from_v); SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { if (totpoints + (ni.size * 2) < max_preview_vertices) { - int to_v = ni.index; - ss->preview_vert_index_list[totpoints] = from_v; + PBVHVertRef to_v = ni.vertex; + int to_v_i = ni.index; + ss->preview_vert_list[totpoints] = from_v; totpoints++; - ss->preview_vert_index_list[totpoints] = to_v; + ss->preview_vert_list[totpoints] = to_v; totpoints++; - if (BLI_BITMAP_TEST(visited_vertices, to_v)) { + if (BLI_BITMAP_TEST(visited_vertices, to_v_i)) { continue; } - BLI_BITMAP_ENABLE(visited_vertices, to_v); + BLI_BITMAP_ENABLE(visited_vertices, to_v_i); const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); if (len_squared_v3v3(brush_co, co) < radius * radius) { BLI_gsqueue_push(not_visited_vertices, &to_v); @@ -609,152 +614,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float MEM_freeN(visited_vertices); - ss->preview_vert_index_count = totpoints; -} - -static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - const MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - const MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - const MLoop *c_loop = &loops[c_poly->loopstart + j]; - float srgb_color[4]; - linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color); - loopcols[loop_index].r = (char)(srgb_color[0] * 255); - loopcols[loop_index].g = (char)(srgb_color[1] * 255); - loopcols[loop_index].b = (char)(srgb_color[2] * 255); - loopcols[loop_index].a = (char)(srgb_color[3] * 255); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static bool sculpt_colors_poll(bContext *C) -{ - if (!SCULPT_mode_poll(C)) { - return false; - } - - Object *ob = CTX_data_active_object(C); - - if (!ob->sculpt || !ob->sculpt->pbvh || BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) { - return false; - } - - return SCULPT_has_colors(ob->sculpt); -} - -static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sculpt Vertex Color to Vertex Color"; - ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; - ot->idname = "SCULPT_OT_vertex_to_loop_colors"; - - /* api callbacks */ - ot->poll = sculpt_colors_poll; - ot->exec = vertex_to_loop_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data == NULL || ID_IS_LINKED(data) || ID_IS_OVERRIDE_LIBRARY(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_PROP_BYTE_COLOR); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - const MLoopCol *loopcols = CustomData_get_layer_n( - &mesh->ldata, CD_PROP_BYTE_COLOR, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - const MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - const MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - const MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - const MLoop *c_loop = &loops[c_poly->loopstart + j]; - vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); - vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); - vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); - vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); - srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Color to Sculpt Vertex Color"; - ot->description = "Copy the active loop color layer to the vertex color"; - ot->idname = "SCULPT_OT_loop_to_vertex_colors"; - - /* api callbacks */ - ot->poll = sculpt_colors_poll; - ot->exec = loop_to_vertex_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ss->preview_vert_count = totpoints; } static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e)) @@ -764,7 +624,7 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent Object *ob = CTX_data_active_object(C); Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; - int active_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); float active_vertex_color[4]; if (!SCULPT_handles_colors_report(ss, op->reports)) { @@ -890,8 +750,11 @@ static void do_mask_by_color_contiguous_update_nodes_cb( } static bool sculpt_mask_by_color_contiguous_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + MaskByColorContiguousFloodFillData *data = userdata; float current_color[4]; @@ -899,10 +762,10 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb( float new_vertex_mask = sculpt_mask_by_color_delta_get( current_color, data->initial_color, data->threshold, data->invert); - data->new_mask[to_v] = new_vertex_mask; + data->new_mask[to_v_i] = new_vertex_mask; if (is_duplicate) { - data->new_mask[to_v] = data->new_mask[from_v]; + data->new_mask[to_v_i] = data->new_mask[from_v_i]; } float len = len_v3v3(current_color, data->initial_color); @@ -911,7 +774,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb( } static void sculpt_mask_by_color_contiguous(Object *object, - const int vertex, + const PBVHVertRef vertex, const float threshold, const bool invert, const bool preserve_mask) @@ -988,7 +851,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); const float current_mask = *vd.mask; const float new_mask = sculpt_mask_by_color_delta_get(active_color, col, threshold, invert); @@ -1006,7 +869,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, } static void sculpt_mask_by_color_full_mesh(Object *object, - const int vertex, + const PBVHVertRef vertex, const float threshold, const bool invert, const bool preserve_mask) @@ -1061,7 +924,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven SCULPT_undo_push_begin(ob, "Mask by color"); BKE_sculpt_color_layer_create_if_needed(ob); - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); const float threshold = RNA_float_get(op->ptr, "threshold"); const bool invert = RNA_boolean_get(op->ptr, "invert"); const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); @@ -1150,8 +1013,6 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_project_line_gesture); WM_operatortype_append(SCULPT_OT_sample_color); - WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); - WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); WM_operatortype_append(SCULPT_OT_color_filter); WM_operatortype_append(SCULPT_OT_mask_by_color); WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index 3b65124fe02..c494c71f1eb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -81,16 +81,16 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float smooth_color[4]; - SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); blend_color_interpolate_float(col, col, smooth_color, fade); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); } BKE_pbvh_vertex_iter_end; } @@ -168,7 +168,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); /* Density. */ @@ -199,10 +199,10 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); IMB_blend_color_float(col, orig_data.col, buffer_color, brush->blend); CLAMP4(col, 0.0f, 1.0f); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); } BKE_pbvh_vertex_iter_end; } @@ -234,7 +234,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata, } float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); add_v4_v4(swptd->color, col); swptd->tot_samples++; @@ -413,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; @@ -422,7 +422,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]); float no[3]; - SCULPT_vertex_normal_get(ss, vd.index, no); + SCULPT_vertex_normal_get(ss, vd.vertex, no); switch (brush->smear_deform_type) { case BRUSH_SMEAR_DEFORM_DRAG: @@ -455,11 +455,11 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, */ SculptVertexNeighborIter ni2; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni2) { - const float *nco = SCULPT_vertex_co_get(ss, ni2.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni2) { + const float *nco = SCULPT_vertex_co_get(ss, ni2.vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.vertex, ni) { if (ni.index == vd.index) { continue; } @@ -467,13 +467,13 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, float vertex_disp[3]; float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co); /* Weight by how close we are to our target distance from vd.co. */ float w = (1.0f + fabsf(len_v3(vertex_disp) / bstrength - 1.0f)); /* TODO: use cotangents (or at least face areas) here. */ - float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.index), nco); + float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.vertex), nco); if (len > 0.0f) { len = bstrength / len; } @@ -515,9 +515,9 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, blend_color_mix_float(interp_color, interp_color, accum); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); blend_color_interpolate_float(col, ss->cache->prev_colors[vd.index], interp_color, fade); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); } BKE_pbvh_vertex_iter_end; } @@ -531,7 +531,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_vertex_color_get(ss, vd.index, ss->cache->prev_colors[vd.index]); + SCULPT_vertex_color_get(ss, vd.vertex, ss->cache->prev_colors[vd.index]); } BKE_pbvh_vertex_iter_end; } @@ -550,7 +550,9 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (!ss->cache->prev_colors) { ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_color_get(ss, vertex, ss->cache->prev_colors[i]); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc index f51a603ee5d..8a3a3fe7adc 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc +++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc @@ -172,7 +172,15 @@ template<typename ImageBuffer> class PaintingKernel { const float3 face_normal(0.0f, 0.0f, 0.0f); const float mask = 0.0f; const float falloff_strength = SCULPT_brush_strength_factor( - ss, brush, pixel_pos, sqrtf(test.dist), normal, face_normal, mask, 0, thread_id); + ss, + brush, + pixel_pos, + sqrtf(test.dist), + normal, + face_normal, + mask, + BKE_pbvh_make_vref(PBVH_REF_NONE), + thread_id); float4 paint_color = brush_color * falloff_strength * brush_strength; float4 buffer_color; blend_color_mix_float(buffer_color, color, paint_color); diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 6f600489729..d1418c8dc35 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -182,7 +182,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, /* Apply the vertex mask to the displacement. */ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); mul_v3_fl(disp, mask * automask); /* Accumulate the displacement. */ @@ -196,7 +196,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, copy_v3_v3(target_co, final_pos); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -221,7 +221,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, float max = 0.0f; /* Grow the factor. */ - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; max = MAX2(vmask_f, max); } @@ -367,7 +367,7 @@ typedef struct PoseFloodFillData { int current_face_set; int next_face_set; int prev_face_set; - int next_vertex; + PBVHVertRef next_vertex; bool next_face_set_found; @@ -397,14 +397,19 @@ typedef struct PoseFloodFillData { int target_face_set; } PoseFloodFillData; -static bool pose_topology_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) +static bool pose_topology_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool is_duplicate, + void *userdata) { + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + PoseFloodFillData *data = userdata; const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { - data->pose_factor[to_v] = 1.0f; + data->pose_factor[to_v_i] = 1.0f; } if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < @@ -426,15 +431,19 @@ static bool pose_topology_floodfill_cb( return false; } -static bool pose_face_sets_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) +static bool pose_face_sets_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool is_duplicate, + void *userdata) { PoseFloodFillData *data = userdata; - const int index = to_v; + const int index = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + const PBVHVertRef vertex = to_v; bool visit_next = false; - const float *co = SCULPT_vertex_co_get(ss, index); + const float *co = SCULPT_vertex_co_get(ss, vertex); const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry( co, data->pose_initial_co, data->symm) && !is_duplicate; @@ -448,11 +457,11 @@ static bool pose_face_sets_floodfill_cb( if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { - const int visited_face_set = SCULPT_vertex_face_set_get(ss, index); + const int visited_face_set = SCULPT_vertex_face_set_get(ss, vertex); BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set)); } else if (symmetry_check) { - data->current_face_set = SCULPT_vertex_face_set_get(ss, index); + data->current_face_set = SCULPT_vertex_face_set_get(ss, vertex); BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set)); } return true; @@ -466,11 +475,11 @@ static bool pose_face_sets_floodfill_cb( GSetIterator gs_iter; GSET_ITER (gs_iter, data->visited_face_sets) { const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set); + is_vertex_valid |= SCULPT_vertex_has_face_set(ss, vertex, visited_face_set); } } else { - is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set); + is_vertex_valid = SCULPT_vertex_has_face_set(ss, vertex, data->current_face_set); } if (!is_vertex_valid) { @@ -485,11 +494,11 @@ static bool pose_face_sets_floodfill_cb( /* Fallback origin accumulation. */ if (symmetry_check) { - add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index)); + add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, vertex)); data->fallback_count++; } - if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, index)) { + if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, vertex)) { return visit_next; } @@ -498,15 +507,15 @@ static bool pose_face_sets_floodfill_cb( bool count_as_boundary = false; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.vertex); /* Check if we can get a valid face set for the next iteration from this neighbor. */ - if (SCULPT_vertex_has_unique_face_set(ss, ni.index) && + if (SCULPT_vertex_has_unique_face_set(ss, ni.vertex) && !BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) { if (!data->next_face_set_found) { data->next_face_set = next_face_set_candidate; - data->next_vertex = ni.index; + data->next_vertex = ni.vertex; data->next_face_set_found = true; } count_as_boundary = true; @@ -516,7 +525,7 @@ static bool pose_face_sets_floodfill_cb( /* Origin accumulation. */ if (count_as_boundary) { - add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index)); + add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, vertex)); data->tot_co++; } return visit_next; @@ -585,7 +594,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata, SculptVertexNeighborIter ni; float avg = 0.0f; int total = 0; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { avg += data->pose_factor[ni.index]; total++; } @@ -660,7 +669,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, float next_chain_segment_target[3]; int totvert = SCULPT_vertex_count_get(ss); - int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true); + PBVHVertRef nearest_vertex = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true); + int nearest_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, nearest_vertex); /* Init the buffers used to keep track of the changes in the pose factors as more segments are * added to the IK chain. */ @@ -745,7 +755,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( int current_face_set = SCULPT_FACE_SET_NONE; int prev_face_set = SCULPT_FACE_SET_NONE; - int current_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef current_vertex = SCULPT_active_vertex_get(ss); for (int s = 0; s < ik_chain->tot_segments; s++) { @@ -801,15 +811,18 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( } static bool pose_face_sets_fk_find_masked_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!is_duplicate) { - data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1; + data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i] + 1; } else { - data->floodfill_it[to_v] = data->floodfill_it[from_v]; + data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i]; } const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v); @@ -820,9 +833,9 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb( BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(to_face_set)); - if (data->floodfill_it[to_v] >= data->masked_face_set_it) { + if (data->floodfill_it[to_v_i] >= data->masked_face_set_it) { data->masked_face_set = to_face_set; - data->masked_face_set_it = data->floodfill_it[to_v]; + data->masked_face_set_it = data->floodfill_it[to_v_i]; } if (data->target_face_set == SCULPT_FACE_SET_NONE) { @@ -834,11 +847,17 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb( return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set); } -static bool pose_face_sets_fk_set_weights_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool pose_face_sets_fk_set_weights_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { PoseFloodFillData *data = userdata; - data->fk_weights[to_v] = 1.0f; + + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + + data->fk_weights[to_v_i] = 1.0f; return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set); } @@ -849,7 +868,9 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert); - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); + int active_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex); + const int active_face_set = SCULPT_active_face_set_get(ss); SculptFloodFill flood; @@ -857,7 +878,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( SCULPT_floodfill_add_initial(&flood, active_vertex); PoseFloodFillData fdata; fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration"); - fdata.floodfill_it[active_vertex] = 1; + fdata.floodfill_it[active_vertex_index] = 1; fdata.initial_face_set = active_face_set; fdata.masked_face_set = SCULPT_FACE_SET_NONE; fdata.target_face_set = SCULPT_FACE_SET_NONE; @@ -870,9 +891,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( int origin_count = 0; float origin_acc[3] = {0.0f}; for (int i = 0; i < totvert; i++) { - if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && - SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) { - add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (fdata.floodfill_it[i] != 0 && + SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, vertex, fdata.masked_face_set)) { + add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, vertex)); origin_count++; } } @@ -881,10 +905,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( float target_acc[3] = {0.0f}; if (fdata.target_face_set != fdata.masked_face_set) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (fdata.floodfill_it[i] != 0 && - SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && - SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) { - add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, vertex, fdata.target_face_set)) { + add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, vertex)); target_count++; } } diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index d6b9b500501..2ef3c28ba0c 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -46,26 +46,28 @@ #include <math.h> #include <stdlib.h> -void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index) +void SCULPT_neighbor_coords_average_interior(SculptSession *ss, + float result[3], + PBVHVertRef vertex) { float avg[3] = {0.0f, 0.0f, 0.0f}; int total = 0; int neighbor_count = 0; - const bool is_boundary = SCULPT_vertex_is_boundary(ss, index); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { neighbor_count++; if (is_boundary) { /* Boundary vertices use only other boundary vertices. */ - if (SCULPT_vertex_is_boundary(ss, ni.index)) { - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + if (SCULPT_vertex_is_boundary(ss, ni.vertex)) { + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } } else { /* Interior vertices use all neighbors. */ - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } } @@ -73,13 +75,13 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], /* Do not modify corner vertices. */ if (neighbor_count <= 2 && is_boundary) { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); return; } /* Avoid division by 0 when there are no neighbors. */ if (total == 0) { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); return; } @@ -134,14 +136,14 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert /* Generic functions for laplacian smoothing. These functions do not take boundary vertices into * account. */ -void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index) +void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex) { float avg[3] = {0.0f, 0.0f, 0.0f}; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -150,18 +152,18 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde mul_v3_v3fl(result, avg, 1.0f / total); } else { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); } } -float SCULPT_neighbor_mask_average(SculptSession *ss, int index) +float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex) { float avg = 0.0f; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - avg += SCULPT_vertex_mask_get(ss, ni.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + avg += SCULPT_vertex_mask_get(ss, ni.vertex); total++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -169,19 +171,19 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index) if (total > 0) { return avg / total; } - return SCULPT_vertex_mask_get(ss, index); + return SCULPT_vertex_mask_get(ss, vertex); } -void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index) +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex) { float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f}; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { float tmp[4] = {0}; - SCULPT_vertex_color_get(ss, ni.index, tmp); + SCULPT_vertex_color_get(ss, ni.vertex, tmp); add_v4_v4(avg, tmp); total++; @@ -192,7 +194,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index mul_v4_v4fl(result, avg, 1.0f / total); } else { - SCULPT_vertex_color_get(ss, index, result); + SCULPT_vertex_color_get(ss, vertex, result); } } @@ -227,7 +229,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp[3]; @@ -235,7 +237,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, disp); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -258,9 +260,11 @@ static void SCULPT_enhance_details_brush(Sculpt *sd, totvert, sizeof(float[3]), "details directions"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); } } @@ -309,22 +313,22 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), - vd.index, + vd.vertex, thread_id); if (smooth_mask) { - float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; + float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask; val *= fade * bstrength; *vd.mask += val; CLAMP(*vd.mask, 0.0f, 1.0f); } else { float avg[3], val[3]; - SCULPT_neighbor_coords_average_interior(ss, avg, vd.index); + SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex); sub_v3_v3v3(val, avg, vd.co); madd_v3_v3v3fl(val, vd.co, val, fade); SCULPT_clip(sd, ss, vd.co, val); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } } @@ -403,13 +407,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, float *disp, const float co[3], float (*laplacian_disp)[3], - const int v_index, + const PBVHVertRef vertex, const float origco[3], const float alpha) { float laplacian_smooth_co[3]; float weigthed_o[3], weigthed_q[3], d[3]; - SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index); + int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + + SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, vertex); mul_v3_v3fl(weigthed_o, origco, alpha); mul_v3_v3fl(weigthed_q, co, 1.0f - alpha); @@ -422,7 +428,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, void SCULPT_surface_smooth_displace_step(SculptSession *ss, float *co, float (*laplacian_disp)[3], - const int v_index, + const PBVHVertRef vertex, const float beta, const float fade) { @@ -430,12 +436,15 @@ void SCULPT_surface_smooth_displace_step(SculptSession *ss, float b_current_vertex[3]; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { add_v3_v3(b_avg, laplacian_disp[ni.index]); total++; } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { + int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total); madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta); mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f)); @@ -474,15 +483,15 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp[3]; SCULPT_surface_smooth_laplacian_step( - ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, orig_data.co, alpha); + ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, orig_data.co, alpha); madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f)); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -515,10 +524,10 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_surface_smooth_displace_step( - ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade); + ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade); } BKE_pbvh_vertex_iter_end; } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 2a7c6c8d0e0..7207e6c35d4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -179,7 +179,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata, add_v3_v3v3(vd.co, start_co, disp); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -253,7 +253,7 @@ static void sculpt_elastic_transform_task_cb(void *__restrict userdata, copy_v3_v3(proxy[vd.i], final_disp); if (vd.mvert) { - BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.index); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index d37d0d2681f..dc814d6d22f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -297,20 +297,20 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); - BKE_pbvh_vert_tag_update_normal(ss->pbvh, index[i]); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } else { for (int i = 0; i < unode->totvert; i++) { swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); - BKE_pbvh_vert_tag_update_normal(ss->pbvh, index[i]); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } } else { for (int i = 0; i < unode->totvert; i++) { swap_v3_v3(mvert[index[i]].co, unode->co[i]); - BKE_pbvh_vert_tag_update_normal(ss->pbvh, index[i]); + BKE_pbvh_vert_tag_update_normal(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } } diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index dfa85e8e56d..2e2abd30ea2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -414,9 +414,8 @@ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op) if (data->timer) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer); } - if (data->elementMap) { - BM_uv_element_map_free(data->elementMap); - } + BM_uv_element_map_free(data->elementMap); + data->elementMap = NULL; MEM_SAFE_FREE(data->uv); MEM_SAFE_FREE(data->uvedges); if (data->initial_stroke) { @@ -435,7 +434,7 @@ static int uv_element_offset_from_face_get( if (!element || (doIslands && element->island != island_index)) { return -1; } - return element - map->buf; + return element - map->storage; } static uint uv_edge_hash(const void *key) @@ -469,7 +468,6 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm BKE_curvemapping_init(ts->uvsculpt->paint.brush->curve); if (data) { - int counter = 0, i; ARegion *region = CTX_wm_region(C); float co[2]; BMFace *efa; @@ -492,13 +490,12 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm data->uvsculpt = &ts->uvsculpt->paint; - if (do_island_optimization) { - /* We will need island information */ - data->elementMap = BM_uv_element_map_create(bm, scene, false, true, true); - } - else { - data->elementMap = BM_uv_element_map_create(bm, scene, false, true, false); - } + /* Winding was added to island detection in 5197aa04c6bd + * However the sculpt tools can flip faces, potentially creating orphaned islands. + * See T100132 */ + bool use_winding = false; + data->elementMap = BM_uv_element_map_create( + bm, scene, false, use_winding, do_island_optimization); if (!data->elementMap) { uv_sculpt_stroke_exit(C, op); @@ -519,20 +516,24 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm } /* Count 'unique' UV's */ - for (i = 0; i < data->elementMap->totalUVs; i++) { - if (data->elementMap->buf[i].separate && - (!do_island_optimization || data->elementMap->buf[i].island == island_index)) { - counter++; + int unique_uvs = data->elementMap->total_unique_uvs; + if (do_island_optimization) { + unique_uvs = 0; + for (int i = 0; i < data->elementMap->total_uvs; i++) { + if (data->elementMap->storage[i].separate && + (data->elementMap->storage[i].island == island_index)) { + unique_uvs++; + } } } /* Allocate the unique uv buffers */ - data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs"); - uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs, + data->uv = MEM_mallocN(sizeof(*data->uv) * unique_uvs, "uv_brush_unique_uvs"); + uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->total_uvs, "uv_brush_unique_uv_map"); edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash"); /* we have at most totalUVs edges */ - edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges"); + edges = MEM_mallocN(sizeof(*edges) * data->elementMap->total_uvs, "uv_brush_all_edges"); if (!data->uv || !uniqueUv || !edgeHash || !edges) { MEM_SAFE_FREE(edges); MEM_SAFE_FREE(uniqueUv); @@ -543,12 +544,12 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm return NULL; } - data->totalUniqueUvs = counter; - /* So that we can use this as index for the UvElements */ - counter = -1; + data->totalUniqueUvs = unique_uvs; + /* Index for the UvElements. */ + int counter = -1; /* initialize the unique UVs */ - for (i = 0; i < bm->totvert; i++) { - UvElement *element = data->elementMap->vert[i]; + for (int i = 0; i < bm->totvert; i++) { + UvElement *element = data->elementMap->vertex[i]; for (; element; element = element->next) { if (element->separate) { if (do_island_optimization && (element->island != island_index)) { @@ -568,7 +569,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm data->uv[counter].uv = luv->uv; } /* Pointer arithmetic to the rescue, as always :). */ - uniqueUv[element - data->elementMap->buf] = counter; + uniqueUv[element - data->elementMap->storage] = counter; } } @@ -628,11 +629,13 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm } /* fill the edges with data */ - i = 0; - GHASH_ITER (gh_iter, edgeHash) { - data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); + { + int i = 0; + GHASH_ITER (gh_iter, edgeHash) { + data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); + } + data->totalUvEdges = BLI_ghash_len(edgeHash); } - data->totalUvEdges = BLI_ghash_len(edgeHash); /* cleanup temporary stuff */ BLI_ghash_free(edgeHash, NULL, NULL); @@ -640,7 +643,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* transfer boundary edge property to UV's */ if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) { - for (i = 0; i < data->totalUvEdges; i++) { + for (int i = 0; i < data->totalUvEdges; i++) { if (!data->uvedges[i].flag) { data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY; data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY; @@ -687,7 +690,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm counter = 0; - for (i = 0; i < data->totalUniqueUvs; i++) { + for (int i = 0; i < data->totalUniqueUvs; i++) { float dist, diff[2]; if (data->uv[i].flag & MARK_BOUNDARY) { continue; diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index 7d4f38b1841..b509eae8ea6 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 0a774ee679c..2109d3f9701 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -869,7 +869,8 @@ void uiTemplateImage(uiLayout *layout, uiItemS(col); uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, IFACE_("Type"), ICON_NONE); - if (ima->gen_type == IMA_GENTYPE_BLANK) { + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (base_tile->gen_type == IMA_GENTYPE_BLANK) { uiItemR(col, &imaptr, "generated_color", 0, NULL, ICON_NONE); } } @@ -1211,6 +1212,11 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i ofs += BLI_strncpy_rlen(str + ofs, TIP_(" + Z"), len - ofs); } + eGPUTextureFormat texture_format = IMB_gpu_get_texture_format(ibuf, + ima->flag & IMA_HIGH_BITDEPTH); + const char *texture_format_description = GPU_texture_format_description(texture_format); + ofs += BLI_snprintf_rlen(str + ofs, len - ofs, TIP_(", %s"), texture_format_description); + uiItemL(col, str, ICON_NONE); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 4036f859231..78aaf957a87 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3847,15 +3847,16 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot) static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile) { - float color[4]; - RNA_float_get_array(ptr, "color", color); - int gen_type = RNA_enum_get(ptr, "generated_type"); - int width = RNA_int_get(ptr, "width"); - int height = RNA_int_get(ptr, "height"); + RNA_float_get_array(ptr, "color", tile->gen_color); + tile->gen_type = RNA_enum_get(ptr, "generated_type"); + tile->gen_x = RNA_int_get(ptr, "width"); + tile->gen_y = RNA_int_get(ptr, "height"); bool is_float = RNA_boolean_get(ptr, "float"); - int planes = RNA_boolean_get(ptr, "alpha") ? 32 : 24; - return BKE_image_fill_tile(ima, tile, width, height, color, gen_type, planes, is_float); + tile->gen_flag = is_float ? IMA_GEN_FLOAT : 0; + tile->gen_depth = RNA_boolean_get(ptr, "alpha") ? 32 : 24; + + return BKE_image_fill_tile(ima, tile); } static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout) diff --git a/source/blender/editors/space_image/image_undo.cc b/source/blender/editors/space_image/image_undo.cc index 0fe0414c177..065641c4051 100644 --- a/source/blender/editors/space_image/image_undo.cc +++ b/source/blender/editors/space_image/image_undo.cc @@ -432,7 +432,7 @@ static void utile_decref(UndoImageTile *utile) /** \name Image Undo Buffer * \{ */ -typedef struct UndoImageBuf { +struct UndoImageBuf { struct UndoImageBuf *next, *prev; /** @@ -454,10 +454,8 @@ typedef struct UndoImageBuf { struct { short source; bool use_float; - char gen_type; } image_state; - -} UndoImageBuf; +}; static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf) { @@ -474,7 +472,6 @@ static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf) MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__)); BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name)); - ubuf->image_state.gen_type = image->gen_type; ubuf->image_state.source = image->source; ubuf->image_state.use_float = ibuf->rect_float != nullptr; @@ -552,7 +549,7 @@ static void ubuf_free(UndoImageBuf *ubuf) /** \name Image Undo Handle * \{ */ -typedef struct UndoImageHandle { +struct UndoImageHandle { struct UndoImageHandle *next, *prev; /** Each undo handle refers to a single image which may have multiple buffers. */ @@ -567,8 +564,7 @@ typedef struct UndoImageHandle { * List of #UndoImageBuf's to support multiple buffers per image. */ ListBase buffers; - -} UndoImageHandle; +}; static void uhandle_restore_list(ListBase *undo_handles, bool use_init) { diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index 29a7eb150a1..e41ff02254b 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -439,14 +439,7 @@ static void stats_update(Depsgraph *depsgraph, } else if (ob && (ob->mode & OB_MODE_SCULPT)) { /* Sculpt Mode. */ - if (stats_is_object_dynamic_topology_sculpt(ob)) { - /* Dynamic topology. Do not count all vertices, - * dynamic topology stats are initialized later as part of sculpt stats. */ - } - else { - /* When dynamic topology is not enabled both sculpt stats and scene stats are collected. */ - stats_object_sculpt(ob, stats); - } + stats_object_sculpt(ob, stats); } else { /* Objects. */ diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index c524de2c55d..9014e36c4e2 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -232,6 +232,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_boolean_set(&ptr, "view2d_edge_pan", true); + RNA_boolean_set(&ptr, "remove_on_cancel", true); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); WM_operator_properties_free(&ptr); } diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index a89b5444a4d..0d498d07aff 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -49,29 +49,48 @@ namespace blender::ed::space_node { /** \name Utilities * \{ */ -bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy) +static void position_node_based_on_mouse(bNode &node, const float2 &location) +{ + node.locx = location.x - NODE_DY * 1.5f / UI_DPI_FAC; + node.locy = location.y + NODE_DY * 0.5f / UI_DPI_FAC; +} + +bNode *add_node(const bContext &C, const StringRef idname, const float2 &location) { SpaceNode &snode = *CTX_wm_space_node(&C); Main &bmain = *CTX_data_main(&C); - bNode *node = nullptr; node_deselect_all(snode); - if (idname) { - node = nodeAddNode(&C, snode.edittree, idname); - } - else { - node = nodeAddStaticNode(&C, snode.edittree, type); - } + const std::string idname_str = idname; + + bNode *node = nodeAddNode(&C, snode.edittree, idname_str.c_str()); BLI_assert(node && node->typeinfo); - /* Position mouse in node header. */ - node->locx = locx - NODE_DY * 1.5f / UI_DPI_FAC; - node->locy = locy + NODE_DY * 0.5f / UI_DPI_FAC; + position_node_based_on_mouse(*node, location); nodeSetSelected(node, true); + ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); + + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); + return node; +} + +bNode *add_static_node(const bContext &C, int type, const float2 &location) +{ + SpaceNode &snode = *CTX_wm_space_node(&C); + Main &bmain = *CTX_data_main(&C); + + node_deselect_all(snode); + + bNode *node = nodeAddStaticNode(&C, snode.edittree, type); + BLI_assert(node && node->typeinfo); + position_node_based_on_mouse(*node, location); + + nodeSetSelected(node, true); ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); return node; } @@ -338,9 +357,9 @@ static int node_add_group_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeTree *node_group; - if (!(node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree))) { + bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree); + if (!node_group) { return OPERATOR_CANCELLED; } @@ -352,12 +371,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - bNode *group_node = node_add_node(*C, - node_idname, - (node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP : - NODE_GROUP, - snode->runtime->cursor[0], - snode->runtime->cursor[1]); + bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor); if (!group_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node group"); return OPERATOR_CANCELLED; @@ -445,8 +459,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - bNode *object_node = node_add_node( - *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]); + bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor); if (!object_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node object"); return OPERATOR_CANCELLED; @@ -522,7 +535,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNodeTree *ntree = snode.edittree; + bNodeTree &ntree = *snode.edittree; Collection *collection = reinterpret_cast<Collection *>( WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR)); @@ -533,8 +546,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - bNode *collection_node = node_add_node( - *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor); if (!collection_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node collection"); return OPERATOR_CANCELLED; @@ -550,8 +562,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) socket_data->value = collection; id_us_plus(&collection->id); - nodeSetActive(ntree, collection_node); - ED_node_tree_propagate_change(C, bmain, ntree); + nodeSetActive(&ntree, collection_node); + ED_node_tree_propagate_change(C, bmain, &ntree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -617,11 +629,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNode *node; - Image *ima; int type = 0; - ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + Image *ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); if (!ima) { return OPERATOR_CANCELLED; } @@ -645,7 +655,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *node = add_static_node(*C, type, snode.runtime->cursor); if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add an image node"); @@ -739,7 +749,6 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNode *node; ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK); if (!mask) { @@ -748,8 +757,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - node = node_add_node( - *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *node = add_static_node(*C, CMP_NODE_MASK, snode.runtime->cursor); if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add a mask node"); diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index a926f7e8917..bb520c0537e 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -45,7 +45,12 @@ #include "UI_resources.h" #include "NOD_common.h" +#include "NOD_composite.h" +#include "NOD_geometry.h" +#include "NOD_shader.h" #include "NOD_socket.h" +#include "NOD_texture.h" + #include "node_intern.hh" /* own include */ namespace blender::ed::space_node { @@ -100,16 +105,16 @@ const char *node_group_idname(bContext *C) SpaceNode *snode = CTX_wm_space_node(C); if (ED_node_is_shader(snode)) { - return "ShaderNodeGroup"; + return ntreeType_Shader->group_idname; } if (ED_node_is_compositor(snode)) { - return "CompositorNodeGroup"; + return ntreeType_Composite->group_idname; } if (ED_node_is_texture(snode)) { - return "TextureNodeGroup"; + return ntreeType_Texture->group_idname; } if (ED_node_is_geometry(snode)) { - return "GeometryNodeGroup"; + return ntreeType_Geometry->group_idname; } return ""; diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 924537d0e8a..81c2bc0e962 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -245,12 +245,9 @@ void draw_nodespace_back_pix(const bContext &C, /* node_add.cc */ -/** - * XXX Does some additional initialization on top of #nodeAddNode - * Can be used with both custom and static nodes, - * if `idname == nullptr` the static int type will be used instead. - */ -bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy); +bNode *add_node(const bContext &C, StringRef idname, const float2 &location); +bNode *add_static_node(const bContext &C, int type, const float2 &location); + void NODE_OT_add_reroute(wmOperatorType *ot); void NODE_OT_add_group(wmOperatorType *ot); void NODE_OT_add_object(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index e10bedb18f4..d911e53be7f 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -639,8 +639,8 @@ static int link_socket_to_viewer(const bContext &C, if (viewer_bnode == nullptr) { /* Create a new viewer node if none exists. */ const int viewer_type = get_default_viewer_type(&C); - viewer_bnode = node_add_node( - C, nullptr, viewer_type, bsocket_to_view.locx + 100, bsocket_to_view.locy); + const float2 location{bsocket_to_view.locx + 100, bsocket_to_view.locy}; + viewer_bnode = add_static_node(C, viewer_type, location); if (viewer_bnode == nullptr) { return OPERATOR_CANCELLED; } @@ -1654,7 +1654,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; - /* XXX save selection: node_add_node call below sets the new frame as single + /* XXX save selection: add_static_node call below sets the new frame as single * active+selected node */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (node->flag & NODE_SELECT) { @@ -1665,7 +1665,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) } } - bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f); + bNode *frame = add_static_node(*C, NODE_FRAME, float2(0)); /* reset tags */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 78ec057f921..b9f79303a06 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -48,11 +48,11 @@ set(SRC tree/tree_element_anim_data.cc tree/tree_element_collection.cc tree/tree_element_driver.cc - tree/tree_element_label.cc tree/tree_element_gpencil_layer.cc tree/tree_element_id.cc tree/tree_element_id_library.cc tree/tree_element_id_scene.cc + tree/tree_element_label.cc tree/tree_element_nla.cc tree/tree_element_overrides.cc tree/tree_element_rna.cc @@ -68,11 +68,11 @@ set(SRC tree/tree_element_anim_data.hh tree/tree_element_collection.hh tree/tree_element_driver.hh - tree/tree_element_label.hh tree/tree_element_gpencil_layer.hh tree/tree_element_id.hh tree/tree_element_id_library.hh tree/tree_element_id_scene.hh + tree/tree_element_label.hh tree/tree_element_nla.hh tree/tree_element_overrides.hh tree/tree_element_rna.hh diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc index 8ca2ffe6a9c..7d0a0a921e4 100644 --- a/source/blender/editors/space_outliner/outliner_collections.cc +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -72,7 +72,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); return lc->collection; } if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { @@ -88,7 +88,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); + struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { @@ -105,7 +105,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); + struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { @@ -184,7 +184,7 @@ struct CollectionNewData { static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) { - struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata); + struct CollectionNewData *data = static_cast<CollectionNewData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { @@ -286,7 +286,7 @@ struct CollectionEditData { static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata) { - CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); + CollectionEditData *data = static_cast<CollectionEditData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { @@ -339,7 +339,7 @@ void outliner_collection_delete( /* Effectively delete the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); /* Test in case collection got deleted as part of another one. */ @@ -444,12 +444,12 @@ struct CollectionObjectsSelectData { static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata) { - CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata); + CollectionObjectsSelectData *data = static_cast<CollectionObjectsSelectData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { case TSE_LAYER_COLLECTION: - data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); + data->layer_collection = static_cast<LayerCollection *>(te->directdata); return TRAVERSE_BREAK; case TSE_R_LAYER: case TSE_SCENE_COLLECTION_BASE: @@ -538,7 +538,7 @@ struct CollectionDuplicateData { static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) { - CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata); + CollectionDuplicateData *data = static_cast<CollectionDuplicateData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { @@ -701,7 +701,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) /* Effectively link the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_collection_child_add(bmain, active_collection, collection); id_fake_user_clear(&collection->id); @@ -762,7 +762,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); while (BKE_collection_cycle_find(active_lc->collection, collection)) { @@ -772,7 +772,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) /* Effectively instance the collections. */ GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); Object *ob = ED_object_add_type( C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0); @@ -814,14 +814,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot) static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata) { - CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); + CollectionEditData *data = static_cast<CollectionEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { return TRAVERSE_CONTINUE; } - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* skip - showing warning/error message might be misleading @@ -862,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>( + LayerCollection *lc = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (clear && (lc->flag & flag)) { @@ -934,7 +934,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>( + LayerCollection *lc = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_flag(lc, flag, !clear); } @@ -1068,7 +1068,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (extend) { @@ -1168,7 +1168,7 @@ static int collection_visibility_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside); } @@ -1319,7 +1319,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); Collection *collection = layer_collection->collection; if (!BKE_id_is_editable(bmain, &collection->id)) { @@ -1348,7 +1348,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (!BKE_id_is_editable(bmain, &collection->id)) { continue; @@ -1451,7 +1451,7 @@ struct OutlinerHideEditData { static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata) { - OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata); + OutlinerHideEditData *data = static_cast<OutlinerHideEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (tselem == nullptr) { @@ -1459,7 +1459,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* Skip - showing warning/error message might be misleading @@ -1501,7 +1501,7 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, false, false); } @@ -1509,7 +1509,7 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator bases_to_edit_iter; GSET_ITER (bases_to_edit_iter, data.bases_to_edit) { - Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter)); + Base *base = static_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter)); base->flag |= BASE_HIDDEN; } BLI_gset_free(data.bases_to_edit, nullptr); @@ -1542,8 +1542,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) ViewLayer *view_layer = CTX_data_view_layer(C); /* Unhide all the collections. */ - LayerCollection *lc_master = reinterpret_cast<LayerCollection *>( - view_layer->layer_collections.first); + LayerCollection *lc_master = static_cast<LayerCollection *>(view_layer->layer_collections.first); LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) { BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false); } diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 7435fa50a93..2fa512b4006 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -144,7 +144,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C, return te_hovered; } *r_insert_type = TE_INSERT_BEFORE; - return reinterpret_cast<TreeElement *>(te_hovered->subtree.first); + return static_cast<TreeElement *>(te_hovered->subtree.first); } *r_insert_type = TE_INSERT_AFTER; return te_hovered; @@ -159,8 +159,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C, /* Mouse doesn't hover any item (ignoring x-axis), * so it's either above list bounds or below. */ - TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first); - TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last); + TreeElement *first = static_cast<TreeElement *>(space_outliner->tree.first); + TreeElement *last = static_cast<TreeElement *>(space_outliner->tree.last); if (view_mval[1] < last->ys) { *r_insert_type = TE_INSERT_AFTER; @@ -422,12 +422,12 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); parent_drop_set_parents(C, op->reports, - reinterpret_cast<wmDragID *>(drag->ids.first), + static_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->modifier & KM_ALT); @@ -505,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { if (GS(drag_id->id->name) == ID_OB) { @@ -849,7 +849,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) ARegion *region = CTX_wm_region(C); bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); if (!drop_data) { return false; } @@ -887,7 +887,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C), const int UNUSED(xy[2]), struct wmDropBox *UNUSED(drop)) { - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_REORDER: return BLI_strdup(TIP_("Reorder")); @@ -965,14 +965,13 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) case TSE_MODIFIER: if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { ED_object_gpencil_modifier_copy_to_object( - ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata)); + ob_dst, static_cast<GpencilModifierData *>(drop_data->drag_directdata)); } else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { - ED_object_modifier_copy_to_object( - C, - ob_dst, - drop_data->ob_parent, - reinterpret_cast<ModifierData *>(drop_data->drag_directdata)); + ED_object_modifier_copy_to_object(C, + ob_dst, + drop_data->ob_parent, + static_cast<ModifierData *>(drop_data->drag_directdata)); } break; case TSE_CONSTRAINT: @@ -980,12 +979,12 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) ED_object_constraint_copy_for_pose( bmain, ob_dst, - reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata), - reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); + static_cast<bPoseChannel *>(drop_data->drop_te->directdata), + static_cast<bConstraint *>(drop_data->drag_directdata)); } else { ED_object_constraint_copy_for_object( - bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); + bmain, ob_dst, static_cast<bConstraint *>(drop_data->drag_directdata)); } break; case TSE_GPENCIL_EFFECT: { @@ -993,8 +992,7 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) return; } - ED_object_shaderfx_copy(ob_dst, - reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata)); + ED_object_shaderfx_copy(ob_dst, static_cast<ShaderFxData *>(drop_data->drag_directdata)); break; } } @@ -1021,15 +1019,12 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa index = outliner_get_insert_index( drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); ED_object_gpencil_modifier_move_to_index( - reports, - ob, - reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata), - index); + reports, ob, static_cast<GpencilModifierData *>(drop_data->drag_directdata), index); } else { index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers); ED_object_modifier_move_to_index( - reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index); + reports, ob, static_cast<ModifierData *>(drop_data->drag_directdata), index); } break; case TSE_CONSTRAINT: @@ -1041,13 +1036,13 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints); } ED_object_constraint_move_to_index( - ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index); + ob, static_cast<bConstraint *>(drop_data->drag_directdata), index); break; case TSE_GPENCIL_EFFECT: index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx); ED_object_shaderfx_move_to_index( - reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index); + reports, ob, static_cast<ShaderFxData *>(drop_data->drag_directdata), index); } } @@ -1057,9 +1052,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_LINK: @@ -1143,7 +1138,7 @@ static bool collection_drop_init(bContext *C, wmDrag *drag, const int xy[2], Col return false; } - wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first); + wmDragID *drag_id = static_cast<wmDragID *>(drag->ids.first); if (drag_id == nullptr) { return false; } @@ -1300,8 +1295,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); CollectionDrop data; if (!collection_drop_init(C, drag, event->xy, &data)) { diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index ae9ffffd145..8bc1ed8c84e 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -277,8 +277,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, Object *ob_parent = ob ? ob : base->object; - for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter; - ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) { + for (Object *ob_iter = static_cast<Object *>(bmain->objects.first); ob_iter; + ob_iter = static_cast<Object *>(ob_iter->id.next)) { if (BKE_object_is_child_recursive(ob_parent, ob_iter)) { if (ob) { RNA_id_pointer_create(&ob_iter->id, &ptr); @@ -312,8 +312,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, */ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Object *ob = reinterpret_cast<Object *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Object *ob = static_cast<Object *>(poin); + char *propname = static_cast<char *>(poin2); outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname); } @@ -322,8 +322,8 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void */ static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Base *base = reinterpret_cast<Base *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Base *base = static_cast<Base *>(poin); + char *propname = static_cast<char *>(poin2); outliner_object_set_flag_recursive_fn(C, base, nullptr, propname); } @@ -488,7 +488,7 @@ void outliner_collection_isolate_flag(Scene *scene, const bool is_hide = strstr(propname, "hide_") != nullptr; LayerCollection *top_layer_collection = layer_collection ? - reinterpret_cast<LayerCollection *>( + static_cast<LayerCollection *>( view_layer->layer_collections.first) : nullptr; Collection *top_collection = collection ? scene->master_collection : nullptr; @@ -559,7 +559,7 @@ void outliner_collection_isolate_flag(Scene *scene, else { CollectionParent *parent; Collection *child = collection; - while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) { + while ((parent = static_cast<CollectionParent *>(child->parents.first))) { if (parent->collection->flag & COLLECTION_IS_MASTER) { break; } @@ -638,8 +638,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + LayerCollection *layer_collection = static_cast<LayerCollection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname); } @@ -649,8 +649,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, */ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + LayerCollection *layer_collection = static_cast<LayerCollection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn( C, layer_collection, layer_collection->collection, propname); } @@ -661,8 +661,8 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin */ static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Collection *collection = reinterpret_cast<Collection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Collection *collection = static_cast<Collection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname); } @@ -672,7 +672,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); struct wmMsgBus *mbus = CTX_wm_message_bus(C); BLI_mempool *ts = space_outliner->treestore; - TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep); + TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep); if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); @@ -737,7 +737,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) switch (tselem->type) { case TSE_DEFGROUP: { Object *ob = (Object *)tselem->id; - bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata); + bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata); BKE_object_defgroup_unique_name(vg, ob); WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name); break; @@ -752,7 +752,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; if (arm->edbo) { - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); char newname[sizeof(ebone->name)]; /* restore bone name */ @@ -770,7 +770,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) outliner_viewcontext_init(C, &tvc); bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); char newname[sizeof(bone->name)]; /* always make current object active */ @@ -790,7 +790,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) Object *ob = (Object *)tselem->id; bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); char newname[sizeof(pchan->name)]; /* always make current pose-bone active */ @@ -801,15 +801,14 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); - ED_armature_bone_rename( - bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname); + ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); break; } case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; /* id = object. */ - bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata); + bActionGroup *grp = static_cast<bActionGroup *>(te->directdata); BLI_uniquename(&ob->pose->agroups, grp, @@ -823,7 +822,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_GP_LAYER: { bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ - bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); + bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata); /* always make layer active */ BKE_gpencil_layer_active_set(gpd, gpl); @@ -839,7 +838,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_R_LAYER: { Scene *scene = (Scene *)tselem->id; - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); /* Restore old name. */ char newname[sizeof(view_layer->name)]; @@ -991,7 +990,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene, { TreeStoreElem *tselem = TREESTORE(te); LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - reinterpret_cast<LayerCollection *>(te->directdata) : + static_cast<LayerCollection *>(te->directdata) : nullptr; Collection *collection = outliner_collection_from_tree_element(te); @@ -1105,7 +1104,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) { /* View layer render toggle. */ - ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *layer = static_cast<ViewLayer *>(te->directdata); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, @@ -1329,7 +1328,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); @@ -1479,8 +1478,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - reinterpret_cast<LayerCollection *>( - te->directdata) : + static_cast<LayerCollection *>(te->directdata) : nullptr; Collection *collection = outliner_collection_from_tree_element(te); @@ -2518,7 +2516,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; break; case TSE_CONSTRAINT: { - bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata); + bConstraint *con = static_cast<bConstraint *>(te->directdata); data.drag_id = tselem->id; switch ((eBConstraint_Types)con->type) { case CONSTRAINT_TYPE_CAMERASOLVER: @@ -2635,9 +2633,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; if (ob->type != OB_GPENCIL) { - ModifierData *md = reinterpret_cast<ModifierData *>( - BLI_findlink(&ob->modifiers, tselem->nr)); - const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>( + ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr)); + const ModifierTypeInfo *modifier_type = static_cast<const ModifierTypeInfo *>( BKE_modifier_get_info((ModifierType)md->type)); if (modifier_type != nullptr) { data.icon = modifier_type->icon; @@ -2648,7 +2645,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } else { /* grease pencil modifiers */ - GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>( + GpencilModifierData *md = static_cast<GpencilModifierData *>( BLI_findlink(&ob->greasepencil_modifiers, tselem->nr)); switch ((GpencilModifierType)md->type) { case eGpencilModifierType_Noise: @@ -2807,7 +2804,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) const PointerRNA &ptr = te_rna_struct->getPointerRNA(); if (RNA_struct_is_ID(ptr.type)) { - data.drag_id = reinterpret_cast<ID *>(ptr.data); + data.drag_id = static_cast<ID *>(ptr.data); data.icon = RNA_struct_ui_icon(ptr.type); } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index 16da4f7b1dd..f22db5d20fc 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -598,9 +598,9 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); - ID *old_id = reinterpret_cast<ID *>( + ID *old_id = static_cast<ID *>( BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"))); - ID *new_id = reinterpret_cast<ID *>( + ID *new_id = static_cast<ID *>( BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"))); /* check for invalid states */ @@ -694,9 +694,9 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C, int i = 0; short id_type = (short)RNA_enum_get(ptr, "id_type"); - ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first); + ID *id = static_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first); - for (; id; id = reinterpret_cast<ID *>(id->next)) { + for (; id; id = static_cast<ID *>(id->next)) { item_tmp.identifier = item_tmp.name = id->name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); @@ -1818,7 +1818,7 @@ static void tree_element_to_path(TreeElement *te, /* ptr->data not ptr->owner_id seems to be the one we want, * since ptr->data is sometimes the owner of this ID? */ if (RNA_struct_is_ID(ptr.type)) { - *id = reinterpret_cast<ID *>(ptr.data); + *id = static_cast<ID *>(ptr.data); /* clear path */ if (*path) { @@ -2053,8 +2053,7 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add) /* try to find one from scene */ if (scene->active_keyingset > 0) { - ks = reinterpret_cast<KeyingSet *>( - BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); + ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); } /* Add if none found */ diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index 877e0fc325c..31ae4aef7ff 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -220,7 +220,7 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te) return; } - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); @@ -239,7 +239,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, { Base *base; - for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) { + for (base = static_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) { Object *ob = base->object; if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { @@ -418,7 +418,7 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement scene->camera = ob; Main *bmain = CTX_data_main(C); - wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first); + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); WM_windows_scene_data_sync(&wm->windows, scene); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); @@ -458,7 +458,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem) { bGPdata *gpd = (bGPdata *)tselem->id; - bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); + bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata); /* We can only have a single "active" layer at a time * and there must always be an active layer... */ @@ -486,8 +486,8 @@ static void tree_element_posechannel_activate(bContext *C, bool recursive) { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bArmature *arm = static_cast<bArmature *>(ob->data); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); if (!(pchan->bone->flag & BONE_HIDDEN_P)) { if (set != OL_SETSEL_EXTEND) { @@ -508,7 +508,7 @@ static void tree_element_posechannel_activate(bContext *C, } if (ob != ob_iter) { - DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); } } MEM_freeN(objects); @@ -541,14 +541,14 @@ static void tree_element_bone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); if (!(bone->flag & BONE_HIDDEN_P)) { Object *ob = OBACT(view_layer); if (ob) { if (set != OL_SETSEL_EXTEND) { /* single select forces all other bones to get unselected */ - for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr; + for (Bone *bone_iter = static_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr; bone_iter = bone_iter->next) { bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); do_outliner_bone_select_recursive(arm, bone_iter, false); @@ -590,7 +590,7 @@ static void tree_element_ebone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); if (set == OL_SETSEL_NORMAL) { if (!(ebone->flag & BONE_HIDDEN_A)) { @@ -703,7 +703,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED #if 0 select_single_seq(seq, 1); #endif - Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first); + Sequence *p = static_cast<Sequence *>(ed->seqbasep->first); while (p) { if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { p = p->next; @@ -722,7 +722,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED static void tree_element_master_collection_activate(const bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( view_layer->layer_collections.first); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work @@ -733,7 +733,7 @@ static void tree_element_master_collection_activate(const bContext *C) static void tree_element_layer_collection_activate(bContext *C, TreeElement *te) { Scene *scene = CTX_data_scene(C); - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata); ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work @@ -857,7 +857,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, const TreeStoreElem *tselem) { const bArmature *arm = (const bArmature *)tselem->id; - const Bone *bone = reinterpret_cast<Bone *>(te->directdata); + const Bone *bone = static_cast<Bone *>(te->directdata); const Object *ob = OBACT(view_layer); if (ob && ob->data == arm) { if (bone->flag & BONE_SELECTED) { @@ -869,7 +869,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, static eOLDrawState tree_element_ebone_state_get(const TreeElement *te) { - const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + const EditBone *ebone = static_cast<EditBone *>(te->directdata); if (ebone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; } @@ -913,7 +913,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose, const TreeStoreElem *tselem) { const Object *ob = (const Object *)tselem->id; - const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + const bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); if (ob == ob_pose && ob->pose) { if (pchan->bone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; @@ -929,7 +929,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr return OL_DRAWSEL_NONE; } - const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + const ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); if (CTX_data_view_layer(C) == view_layer) { return OL_DRAWSEL_NORMAL; @@ -1229,7 +1229,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE /* Expand the selected constraint in the properties editor. */ if (tselem->type != TSE_CONSTRAINT_BASE) { - BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata)); + BKE_constraint_panel_expand(static_cast<bConstraint *>(te->directdata)); } break; } @@ -1242,8 +1242,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE Object *ob = (Object *)tselem->id; if (ob->type == OB_GPENCIL) { - BKE_gpencil_modifier_panel_expand( - reinterpret_cast<GpencilModifierData *>(te->directdata)); + BKE_gpencil_modifier_panel_expand(static_cast<GpencilModifierData *>(te->directdata)); } else { ModifierData *md = (ModifierData *)te->directdata; @@ -1276,12 +1275,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE context = BCONTEXT_SHADERFX; if (tselem->type != TSE_GPENCIL_EFFECT_BASE) { - BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata)); + BKE_shaderfx_panel_expand(static_cast<ShaderFxData *>(te->directdata)); } break; case TSE_BONE: { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); context = BCONTEXT_BONE; @@ -1289,7 +1288,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr); context = BCONTEXT_BONE; @@ -1297,8 +1296,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_CHANNEL: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bArmature *arm = static_cast<bArmature *>(ob->data); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr); context = BCONTEXT_BONE; @@ -1306,7 +1305,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_BASE: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1314,7 +1313,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_R_LAYER_BASE: case TSE_R_LAYER: { - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr); context = BCONTEXT_VIEW_LAYER; @@ -1323,7 +1322,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE case TSE_POSEGRP_BASE: case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1823,7 +1822,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o { while (te->subtree.last) { if (TSELEM_OPEN(TREESTORE(te), space_outliner)) { - te = reinterpret_cast<TreeElement *>(te->subtree.last); + te = static_cast<TreeElement *>(te->subtree.last); } else { break; @@ -1867,7 +1866,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr TreeStoreElem *tselem = TREESTORE(te); if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) { - te = reinterpret_cast<TreeElement *>(te->subtree.first); + te = static_cast<TreeElement *>(te->subtree.first); } else if (te->next) { te = te->next; @@ -1904,7 +1903,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner, /* Only walk down a level if the element is open and not toggling expand */ if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) { - te = reinterpret_cast<TreeElement *>(te->subtree.first); + te = static_cast<TreeElement *>(te->subtree.first); } else { outliner_item_openclose(space_outliner, te, true, toggle_all); @@ -1955,7 +1954,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner /* If no active element exists, use the first element in the tree */ if (!active_te) { - active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first); + active_te = static_cast<TreeElement *>(space_outliner->tree.first); *changed = true; } diff --git a/source/blender/editors/space_outliner/outliner_sync.cc b/source/blender/editors/space_outliner/outliner_sync.cc index 36bc7c31b91..772a5826f9f 100644 --- a/source/blender/editors/space_outliner/outliner_sync.cc +++ b/source/blender/editors/space_outliner/outliner_sync.cc @@ -77,8 +77,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); - for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen; - screen = reinterpret_cast<bScreen *>(screen->id.next)) { + for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen; + screen = static_cast<bScreen *>(screen->id.next)) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { if (sl->spacetype == SPACE_OUTLINER) { @@ -259,7 +259,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te, GSet *selected_pbones) { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); bPoseChannel *pchan = (bPoseChannel *)te->directdata; short bone_flag = pchan->bone->flag; diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 87604818ee1..c408eca654c 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -856,7 +856,7 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; ID *id_root_reference = tselem->id; @@ -1160,7 +1160,7 @@ static void id_override_library_reset_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -1191,7 +1191,7 @@ static void id_override_library_resync_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -1637,7 +1637,7 @@ static void data_select_linked_fn(int event, const PointerRNA &ptr = te_rna_struct->getPointerRNA(); if (RNA_struct_is_ID(ptr.type)) { bContext *C = (bContext *)C_v; - ID *id = reinterpret_cast<ID *>(ptr.data); + ID *id = static_cast<ID *>(ptr.data); ED_object_select_linked_by_id(C, id); } @@ -1646,7 +1646,7 @@ static void data_select_linked_fn(int event, static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) { - bContext *C = reinterpret_cast<bContext *>(C_v); + bContext *C = static_cast<bContext *>(C_v); Main *bmain = CTX_data_main(C); bConstraint *constraint = (bConstraint *)te->directdata; Object *ob = (Object *)outliner_search_back(te, ID_OB); @@ -1737,7 +1737,7 @@ static Base *outliner_batch_delete_hierarchy( } object = base->object; - for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base; + for (child_base = static_cast<Base *>(view_layer->object_bases.first); child_base; child_base = base_next) { base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != object); @@ -1960,7 +1960,7 @@ static void outliner_do_object_delete(bContext *C, static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata) { - ObjectEditData *data = reinterpret_cast<ObjectEditData *>(customdata); + ObjectEditData *data = static_cast<ObjectEditData *>(customdata); GSet *objects_to_delete = data->objects_set; TreeStoreElem *tselem = TREESTORE(te); @@ -2711,8 +2711,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op) get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); /* get action to use */ - act = reinterpret_cast<bAction *>( - BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"))); + act = static_cast<bAction *>(BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"))); if (act == nullptr) { BKE_report(op->reports, RPT_ERROR, "No valid action to add"); diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index 3357a456e30..0906bbb5797 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -90,7 +90,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool_iter iter; BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { tselem->used = 0; } @@ -100,7 +100,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP; BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { if (tselem->id == nullptr) { unused++; } @@ -120,9 +120,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool *new_ts = BLI_mempool_create( sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER); BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { if (tselem->id) { - tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts)); + tsenew = static_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts)); *tsenew = *tselem; } } @@ -151,7 +151,7 @@ static void check_persistent( sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); } if (space_outliner->runtime->treehash == nullptr) { - space_outliner->runtime->treehash = reinterpret_cast<GHash *>( + space_outliner->runtime->treehash = static_cast<GHash *>( BKE_outliner_treehash_create_from_treestore(space_outliner->treestore)); } @@ -166,7 +166,7 @@ static void check_persistent( } /* add 1 element to treestore */ - tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore)); + tselem = static_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore)); tselem->type = type; tselem->nr = type ? nr : 0; tselem->id = id; @@ -293,7 +293,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); TreeElement *tenla = outliner_add_element( space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0); tenla->name = IFACE_("Pose"); @@ -339,7 +339,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } } /* make hierarchy */ - TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first); + TreeElement *ten = static_cast<TreeElement *>(tenla->subtree.first); while (ten) { TreeElement *nten = ten->next, *par; tselem = TREESTORE(ten); @@ -694,15 +694,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, ebone->temp.p = ten; } /* make hierarchy */ - TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>( - ((EditBone *)arm->edbo->first)->temp.p) : - nullptr; + TreeElement *ten = arm->edbo->first ? + static_cast<TreeElement *>(((EditBone *)arm->edbo->first)->temp.p) : + nullptr; while (ten) { TreeElement *nten = ten->next, *par; EditBone *ebone = (EditBone *)ten->directdata; if (ebone->parent) { BLI_remlink(&te->subtree, ten); - par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p); + par = static_cast<TreeElement *>(ebone->parent->temp.p); BLI_addtail(&par->subtree, ten); ten->parent = par; } @@ -805,12 +805,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, short index, const bool expand) { - ID *id = reinterpret_cast<ID *>(idv); + ID *id = static_cast<ID *>(idv); if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { id = ((PointerRNA *)idv)->owner_id; if (!id) { - id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data); + id = static_cast<ID *>(((PointerRNA *)idv)->data); } } else if (type == TSE_GP_LAYER) { @@ -990,8 +990,8 @@ struct tTreeSort { /* alphabetical comparator, trying to put objects first */ static int treesort_alpha_ob(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); /* first put objects last (hierarchy) */ int comp = (x1->idcode == ID_OB); @@ -1029,8 +1029,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2) /* Move children that are not in the collection to the end of the list. */ static int treesort_child_not_in_collection(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); /* Among objects first come the ones in the collection, followed by the ones not on it. * This way we can have the dashed lines in a separate style connecting the former. */ @@ -1043,8 +1043,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2) /* alphabetical comparator */ static int treesort_alpha(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); int comp = BLI_strcasecmp_natural(x1->name, x2->name); @@ -1101,7 +1101,7 @@ static int treesort_obtype_alpha(const void *v1, const void *v2) /* sort happens on each subtree individual */ static void outliner_sort(ListBase *lb) { - TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + TreeElement *last_te = static_cast<TreeElement *>(lb->last); if (last_te == nullptr) { return; } @@ -1113,7 +1113,7 @@ static void outliner_sort(ListBase *lb) int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = reinterpret_cast<tTreeSort *>( + tTreeSort *tear = static_cast<tTreeSort *>( MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; int skip = 0; @@ -1169,7 +1169,7 @@ static void outliner_sort(ListBase *lb) static void outliner_collections_children_sort(ListBase *lb) { - TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + TreeElement *last_te = static_cast<TreeElement *>(lb->last); if (last_te == nullptr) { return; } @@ -1180,7 +1180,7 @@ static void outliner_collections_children_sort(ListBase *lb) int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = reinterpret_cast<tTreeSort *>( + tTreeSort *tear = static_cast<tTreeSort *>( MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; @@ -1551,8 +1551,7 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element, if (outliner_element_is_collection_or_object(element)) { TreeElement *te_prev = nullptr; - for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te; - te = te_prev) { + for (TreeElement *te = static_cast<TreeElement *>(element->subtree.last); te; te = te_prev) { te_prev = te->prev; if (!outliner_element_is_collection_or_object(te)) { @@ -1579,7 +1578,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner, TreeElement *te, *te_next; TreeStoreElem *tselem; - for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) { + for (te = static_cast<TreeElement *>(lb->first); te; te = te_next) { te_next = te->next; if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { /* Don't free the tree, but extract the children from the parent and add to this tree. */ diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc index 0db612ce6db..d8c50cd04f9 100644 --- a/source/blender/editors/space_outliner/outliner_utils.cc +++ b/source/blender/editors/space_outliner/outliner_utils.cc @@ -98,7 +98,7 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement * float view_co_x, bool *r_is_merged_icon) { - TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first); + TreeElement *child_te = static_cast<TreeElement *>(parent_te->subtree.first); while (child_te) { const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend); @@ -282,8 +282,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner, TreeTraversalFunc func, void *customdata) { - for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te; - te = te_next) { + for (TreeElement *te = static_cast<TreeElement *>(tree->first), *te_next; te; te = te_next) { TreeTraversalAction func_retval = TRAVERSE_CONTINUE; /* in case te is freed in callback */ TreeStoreElem *tselem = TREESTORE(te); diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index 5bcd1edebc0..61bc3d35dfd 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -101,7 +101,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) ScrArea *area = params->area; ARegion *region = params->region; wmNotifier *wmn = params->notifier; - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); /* context changes */ switch (wmn->category) { @@ -264,7 +264,7 @@ static void outliner_main_region_message_subscribe(const wmRegionMessageSubscrib struct wmMsgBus *mbus = params->message_bus; ScrArea *area = params->area; ARegion *region = params->region; - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); wmMsgSubscribeValue msg_sub_value_region_tag_redraw{}; msg_sub_value_region_tag_redraw.owner = region; @@ -361,7 +361,7 @@ static void outliner_free(SpaceLink *sl) /* spacetype; init callback */ static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area) { - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); if (space_outliner->runtime == nullptr) { space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime"); @@ -437,7 +437,7 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe static void outliner_deactivate(struct ScrArea *area) { /* Remove hover highlights */ - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY, false); ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc index 349d36e2fe6..e590b0c97d1 100644 --- a/source/blender/editors/space_outliner/tree/common.cc +++ b/source/blender/editors/space_outliner/tree/common.cc @@ -38,7 +38,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb) { /* build hierarchy */ /* XXX also, set extents here... */ - TreeElement *te = reinterpret_cast<TreeElement *>(lb->first); + TreeElement *te = static_cast<TreeElement *>(lb->first); while (te) { TreeElement *ten = te->next; TreeStoreElem *tselem = TREESTORE(te); diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index a401662297a..4a540c3ce87 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -4,6 +4,9 @@ * \ingroup spoutliner */ +#include <string> +#include <string_view> + #include "DNA_anim_types.h" #include "DNA_listBase.h" #include "DNA_space_types.h" @@ -57,7 +60,7 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i return std::make_unique<TreeElementLabel>(legacy_te, static_cast<const char *>(idv)); case TSE_ANIM_DATA: return std::make_unique<TreeElementAnimData>(legacy_te, - *reinterpret_cast<IdAdtTemplate *>(idv)->adt); + *static_cast<IdAdtTemplate *>(idv)->adt); case TSE_DRIVER_BASE: return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv)); case TSE_NLA: @@ -83,22 +86,20 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i return std::make_unique<TreeElementOverridesPropertyOperation>( legacy_te, *static_cast<TreeElementOverridesData *>(idv)); case TSE_RNA_STRUCT: - return std::make_unique<TreeElementRNAStruct>(legacy_te, - *reinterpret_cast<PointerRNA *>(idv)); + return std::make_unique<TreeElementRNAStruct>(legacy_te, *static_cast<PointerRNA *>(idv)); case TSE_RNA_PROPERTY: return std::make_unique<TreeElementRNAProperty>( - legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index); case TSE_RNA_ARRAY_ELEM: return std::make_unique<TreeElementRNAArrayElement>( - legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index); case TSE_SEQUENCE: - return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv)); + return std::make_unique<TreeElementSequence>(legacy_te, *static_cast<Sequence *>(idv)); case TSE_SEQ_STRIP: - return std::make_unique<TreeElementSequenceStrip>(legacy_te, - *reinterpret_cast<Strip *>(idv)); + return std::make_unique<TreeElementSequenceStrip>(legacy_te, *static_cast<Strip *>(idv)); case TSE_SEQUENCE_DUP: - return std::make_unique<TreeElementSequenceStripDuplicate>( - legacy_te, *reinterpret_cast<Sequence *>(idv)); + return std::make_unique<TreeElementSequenceStripDuplicate>(legacy_te, + *static_cast<Sequence *>(idv)); default: break; } @@ -116,6 +117,17 @@ std::optional<BIFIconID> AbstractTreeElement::getIcon() const return {}; } +void AbstractTreeElement::print_path() +{ + std::string path = legacy_te_.name; + + for (TreeElement *parent = legacy_te_.parent; parent; parent = parent->parent) { + path = parent->name + std::string_view("/") + path; + } + + std::cout << path << std::endl; +} + void AbstractTreeElement::uncollapse_by_default(TreeElement *legacy_te) { if (!TREESTORE(legacy_te)->used) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index a3598e7740b..fc6211f20ea 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -75,6 +75,16 @@ class AbstractTreeElement { virtual std::optional<BIFIconID> getIcon() const; /** + * Debugging helper: Print effective path of this tree element, constructed out of the + * #TreeElement.name of each element. E.g.: + * - Lorem + * - ipsum dolor sit + * - amet + * will print: Lorem/ipsum dolor sit/amet. + */ + void print_path(); + + /** * Expand this tree element if it is displayed for the first time (as identified by its * tree-store element). * diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc index 7db6b9635ee..e19459ced61 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc @@ -153,7 +153,7 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const /** \} */ /* -------------------------------------------------------------------- */ -/** \name Overriden Property +/** \name Overridden Property * * Represents an RNA property that was overridden. * @@ -187,7 +187,7 @@ StringRefNull TreeElementOverridesProperty::getWarning() const /** \} */ /* -------------------------------------------------------------------- */ -/** \name Overriden Property Operation +/** \name Overridden Property Operation * * See #TreeElementOverridesPropertyOperation. * \{ */ diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh index acf35033ce1..f8ca146a4ea 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh @@ -66,7 +66,7 @@ class TreeElementOverridesProperty : public AbstractTreeElement { }; /** - * Represent a single operation within an overriden property. While usually a single override + * Represent a single operation within an overridden property. While usually a single override * property represents a single operation (changing the value), a single overridden collection * property may have multiple operations, e.g. to insert or remove collection items. * diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc index 914104f1f06..6dd5ec84041 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -117,7 +117,7 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const for (int index = 0; index < tot; index++) { PointerRNA propptr; RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr); - if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) { + if (!(RNA_property_flag(static_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) { outliner_add_element( &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index); } @@ -146,7 +146,7 @@ TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te, PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type); RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr); - PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data); + PropertyRNA *prop = static_cast<PropertyRNA *>(propptr.data); legacy_te_.name = RNA_property_ui_name(prop); rna_prop_ = prop; @@ -232,8 +232,7 @@ TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te, char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index); - legacy_te_.name = reinterpret_cast<char *>( - MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); + legacy_te_.name = static_cast<char *>(MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); if (c) { sprintf((char *)legacy_te_.name, " %c", c); } diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index f6561cf07b9..4796d80b3a0 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -51,7 +51,9 @@ typedef struct SeqDropCoords { float start_frame, channel; int strip_len, channel_len; + float playback_rate; bool in_use; + bool has_read_mouse_pos; bool is_intersecting; bool use_snapping; float snap_point_x; @@ -63,7 +65,7 @@ typedef struct SeqDropCoords { * preloading data on drag start. * Therefore we will for now use a global variable for this. */ -static SeqDropCoords g_drop_coords = {.in_use = false}; +static SeqDropCoords g_drop_coords = {.in_use = false, .has_read_mouse_pos = false}; static void generic_poll_operations(const wmEvent *event, uint8_t type) { @@ -82,31 +84,134 @@ static bool image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *ev } } - return WM_drag_is_ID_type(drag, ID_IM); + if (WM_drag_is_ID_type(drag, ID_IM)) { + generic_poll_operations(event, TH_SEQ_IMAGE); + return true; + } + + return false; } -static bool movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +static bool is_movie(wmDrag *drag) { if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */ - generic_poll_operations(event, TH_SEQ_MOVIE); + if (ELEM(drag->icon, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */ return true; } } + if (WM_drag_is_ID_type(drag, ID_MC)) { + return true; + } + return false; +} + +static bool movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +{ + if (is_movie(drag)) { + generic_poll_operations(event, TH_SEQ_MOVIE); + return true; + } - return WM_drag_is_ID_type(drag, ID_MC); + return false; } -static bool sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +static bool is_sound(wmDrag *drag) { if (drag->type == WM_DRAG_PATH) { if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* Rule might not work? */ - generic_poll_operations(event, TH_SEQ_AUDIO); return true; } } + if (WM_drag_is_ID_type(drag, ID_SO)) { + return true; + } + return false; +} - return WM_drag_is_ID_type(drag, ID_SO); +static bool sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +{ + if (is_sound(drag)) { + generic_poll_operations(event, TH_SEQ_AUDIO); + return true; + } + + return false; +} + +static float update_overlay_strip_position_data(bContext *C, const int mval[2]) +{ + SeqDropCoords *coords = &g_drop_coords; + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + int hand; + View2D *v2d = ®ion->v2d; + + /* Update the position were we would place the strip if we complete the drag and drop action. + */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &coords->start_frame, &coords->channel); + coords->start_frame = roundf(coords->start_frame); + if (coords->channel < 1.0f) { + coords->channel = 1; + } + + float start_frame = coords->start_frame; + float end_frame; + float strip_len; + + if (coords->playback_rate != 0.0f) { + float scene_playback_rate = (float)scene->r.frs_sec / scene->r.frs_sec_base; + strip_len = coords->strip_len / (coords->playback_rate / scene_playback_rate); + } + else { + strip_len = coords->strip_len; + } + + end_frame = coords->start_frame + strip_len; + + if (coords->use_snapping) { + /* Do snapping via the existing transform code. */ + int snap_delta; + float snap_frame; + bool valid_snap; + + valid_snap = ED_transform_snap_sequencer_to_closest_strip_calc( + scene, region, start_frame, end_frame, &snap_delta, &snap_frame); + + if (valid_snap) { + /* We snapped onto something! */ + start_frame += snap_delta; + coords->start_frame = start_frame; + end_frame = start_frame + strip_len; + coords->snap_point_x = snap_frame; + } + else { + /* Nothing was snapped to, disable snap drawing. */ + coords->use_snapping = false; + } + } + + if (strip_len < 1) { + /* Only check if there is a strip already under the mouse cursor. */ + coords->is_intersecting = find_nearest_seq(scene, ®ion->v2d, &hand, mval); + } + else { + /* Check if there is a strip that would intersect with the new strip(s). */ + coords->is_intersecting = false; + Sequence dummy_seq = {.machine = coords->channel, + .start = coords->start_frame, + .len = coords->strip_len, + .speed_factor = 1.0f, + .media_playback_rate = coords->playback_rate, + .flag = SEQ_AUTO_PLAYBACK_RATE}; + Editing *ed = SEQ_editing_ensure(scene); + + for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) { + coords->is_intersecting = SEQ_transform_test_overlap(scene, ed->seqbasep, &dummy_seq); + dummy_seq.machine++; + } + } + + return strip_len; } static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop) @@ -153,93 +258,77 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop) RNA_collection_add(drop->ptr, "files", &itemptr); RNA_string_set(&itemptr, "name", file); } - - if (g_drop_coords.in_use) { - RNA_int_set(drop->ptr, "frame_start", g_drop_coords.start_frame); - RNA_int_set(drop->ptr, "channel", g_drop_coords.channel); - RNA_boolean_set(drop->ptr, "overlap_shuffle_override", true); - } - else { - Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene); - ListBase *seqbase = SEQ_active_seqbase_get(ed); - ListBase *channels = SEQ_channels_displayed_get(ed); - SpaceSeq *sseq = CTX_wm_space_seq(C); - - SeqCollection *strips = SEQ_query_rendered_strips( - scene, channels, seqbase, scene->r.cfra, sseq->chanshown); - - /* Get the top most strip channel that is in view.*/ - Sequence *seq; - int max_channel = -1; - SEQ_ITERATOR_FOREACH (seq, strips) { - max_channel = max_ii(seq->machine, max_channel); - } - - if (max_channel != -1) { - RNA_int_set(drop->ptr, "channel", max_channel); - } - SEQ_collection_free(strips); - } } -} -static void update_overlay_strip_poistion_data(bContext *C, const int mval[2]) -{ - SeqDropCoords *coords = &g_drop_coords; - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int hand; - View2D *v2d = ®ion->v2d; + if (g_drop_coords.in_use) { + if (!g_drop_coords.has_read_mouse_pos) { + /* We didn't read the mouse position, so we need to do it manually here. */ + int xy[2]; + wmWindow *win = CTX_wm_window(C); + xy[0] = win->eventstate->xy[0]; + xy[1] = win->eventstate->xy[1]; + + ARegion *region = CTX_wm_region(C); + int mval[2]; + /* Convert mouse coordinates to region local coordinates. */ + mval[0] = xy[0] - region->winrct.xmin; + mval[1] = xy[1] - region->winrct.ymin; + + update_overlay_strip_position_data(C, mval); + } - /* Update the position were we would place the strip if we complete the drag and drop action. - */ - UI_view2d_region_to_view(v2d, mval[0], mval[1], &coords->start_frame, &coords->channel); - coords->start_frame = roundf(coords->start_frame); - if (coords->channel < 1.0f) { - coords->channel = 1; + RNA_int_set(drop->ptr, "frame_start", g_drop_coords.start_frame); + RNA_int_set(drop->ptr, "channel", g_drop_coords.channel); + RNA_boolean_set(drop->ptr, "overlap_shuffle_override", true); } + else { + /* We are dropped inside the preview region. Put the strip on top of the + * current displayed frame. */ + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); + SpaceSeq *sseq = CTX_wm_space_seq(C); - float start_frame = coords->start_frame; - float end_frame = coords->start_frame + coords->strip_len; - - if (coords->use_snapping) { - /* Do snapping via the existing transform code. */ - int snap_delta; - float snap_frame; - bool valid_snap; - - valid_snap = ED_transform_snap_sequencer_to_closest_strip_calc( - scene, region, start_frame, end_frame, &snap_delta, &snap_frame); + SeqCollection *strips = SEQ_query_rendered_strips( + scene, channels, seqbase, scene->r.cfra, sseq->chanshown); - if (valid_snap) { - /* We snapped onto something! */ - start_frame += snap_delta; - coords->start_frame = start_frame; - end_frame = start_frame + coords->strip_len; - coords->snap_point_x = snap_frame; + /* Get the top most strip channel that is in view.*/ + Sequence *seq; + int max_channel = -1; + SEQ_ITERATOR_FOREACH (seq, strips) { + max_channel = max_ii(seq->machine, max_channel); } - else { - /* Nothing was snapped to, disable snap drawing. */ - coords->use_snapping = false; + + if (max_channel != -1) { + RNA_int_set(drop->ptr, "channel", max_channel); } + SEQ_collection_free(strips); } +} - if (coords->strip_len < 1) { - /* Only check if there is a strip already under the mouse cursor. */ - coords->is_intersecting = find_nearest_seq(scene, ®ion->v2d, &hand, mval); +static void get_drag_path(wmDrag *drag, char r_path[FILE_MAX]) +{ + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); + /* ID dropped. */ + if (id != NULL) { + const ID_Type id_type = GS(id->name); + if (id_type == ID_IM) { + Image *ima = (Image *)id; + BLI_strncpy(r_path, ima->filepath, FILE_MAX); + } + else if (id_type == ID_MC) { + MovieClip *clip = (MovieClip *)id; + BLI_strncpy(r_path, clip->filepath, FILE_MAX); + } + else if (id_type == ID_SO) { + bSound *sound = (bSound *)id; + BLI_strncpy(r_path, sound->filepath, FILE_MAX); + } + BLI_path_abs(r_path, BKE_main_blendfile_path_from_global()); } else { - /* Check if there is a strip that would intersect with the new strip(s). */ - coords->is_intersecting = false; - Sequence dummy_seq = { - .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len}; - Editing *ed = SEQ_editing_ensure(scene); - - for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) { - coords->is_intersecting = SEQ_transform_test_overlap(scene, ed->seqbasep, &dummy_seq); - dummy_seq.machine++; - } + BLI_strncpy(r_path, drag->path, FILE_MAX); } } @@ -256,7 +345,7 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c mval[0] = xy[0] - region->winrct.xmin; mval[1] = xy[1] - region->winrct.ymin; - update_overlay_strip_poistion_data(C, mval); + float strip_len = update_overlay_strip_position_data(C, mval); GPU_matrix_push(); UI_view2d_view_ortho(®ion->v2d); @@ -280,7 +369,7 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c /* Draw strips. The code here is taken from sequencer_draw. */ float x1 = coords->start_frame; - float x2 = coords->start_frame + coords->strip_len; + float x2 = coords->start_frame + floorf(strip_len); float strip_color[3]; uchar text_color[4] = {255, 255, 255, 255}; float pixelx = BLI_rctf_size_x(®ion->v2d.cur) / BLI_rcti_size_x(®ion->v2d.mask); @@ -354,21 +443,22 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c const char *text_array[5]; char text_display[FILE_MAX]; char filename[FILE_MAX]; - char rel_path[FILE_MAX]; + char path[FILE_MAX]; char strip_duration_text[16]; int len_text_arr = 0; + get_drag_path(drag, path); + if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) { - BLI_split_file_part(drag->path, filename, FILE_MAX); + BLI_split_file_part(path, filename, FILE_MAX); text_array[len_text_arr++] = filename; } if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) { Main *bmain = CTX_data_main(C); - BLI_strncpy(rel_path, drag->path, FILE_MAX); - BLI_path_rel(rel_path, BKE_main_blendfile_path(bmain)); + BLI_path_rel(path, BKE_main_blendfile_path(bmain)); text_array[len_text_arr++] = text_sep; - text_array[len_text_arr++] = rel_path; + text_array[len_text_arr++] = path; } if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { @@ -442,6 +532,14 @@ static void prefetch_data_fn(void *custom_data, if (anim != NULL) { g_drop_coords.strip_len = IMB_anim_get_duration(anim, IMB_TC_NONE); + short frs_sec; + float frs_sec_base; + if (IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base, true)) { + g_drop_coords.playback_rate = (float)frs_sec / frs_sec_base; + } + else { + g_drop_coords.playback_rate = 0; + } IMB_free_anim(anim); #ifdef WITH_AUDASPACE /* Try to load sound and see if the video has a sound channel. */ @@ -464,7 +562,7 @@ static void free_prefetch_data_fn(void *custom_data) MEM_freeN(job_data); } -static void start_audio_video_job(bContext *C, char *path, bool only_audio) +static void start_audio_video_job(bContext *C, wmDrag *drag, bool only_audio) { g_drop_coords.strip_len = 0; g_drop_coords.channel_len = 1; @@ -478,8 +576,8 @@ static void start_audio_video_job(bContext *C, char *path, bool only_audio) DropJobData *job_data = (DropJobData *)MEM_mallocN(sizeof(DropJobData), "SeqDragDropPreviewData"); + get_drag_path(drag, job_data->path); - BLI_strncpy(job_data->path, path, FILE_MAX); job_data->only_audio = only_audio; job_data->scene_fps = FPS; @@ -492,15 +590,15 @@ static void start_audio_video_job(bContext *C, char *path, bool only_audio) static void video_prefetch(bContext *C, wmDrag *drag) { - if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { - start_audio_video_job(C, drag->path, false); + if (is_movie(drag)) { + start_audio_video_job(C, drag, false); } } static void audio_prefetch(bContext *C, wmDrag *drag) { - if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { - start_audio_video_job(C, drag->path, true); + if (is_sound(drag)) { + start_audio_video_job(C, drag, true); } } @@ -534,6 +632,7 @@ static void sequencer_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSE SeqDropCoords *coords = drop->draw_data; if (coords) { coords->in_use = false; + coords->has_read_mouse_pos = false; drop->draw_data = NULL; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index eb2e4ef05e5..0bacbde8240 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -519,7 +519,7 @@ static void draw_seq_waveform_overlay( MEM_freeN(waveform_data); } -/* +#if 0 static size_t *waveform_append(WaveVizData *waveform_data, vec2f pos, const float value_min, @@ -529,7 +529,7 @@ static size_t *waveform_append(WaveVizData *waveform_data, const float rms, const bool is_clipping, const bool is_line_strip) -*/ +#endif static void drawmeta_contents(Scene *scene, Sequence *seqm, diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c index 9af9c5be45a..8125e334492 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c +++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c @@ -22,13 +22,8 @@ #include "view3d_intern.h" #include "view3d_navigate.h" /* own include */ -static void view3d_smoothview_apply_ex(bContext *C, - View3D *v3d, - ARegion *region, - bool sync_boxview, - bool use_autokey, - const float step, - const bool finished); +static void view3d_smoothview_apply_with_interp( + bContext *C, View3D *v3d, ARegion *region, const bool use_autokey, const float factor); /* -------------------------------------------------------------------- */ /** \name Smooth View Undo Handling @@ -115,14 +110,9 @@ void ED_view3d_smooth_view_undo_end(bContext *C, return; } - /* Arguments to #view3d_smoothview_apply_ex to temporarily apply transformation. */ - const bool sync_boxview = false; - const bool use_autokey = false; - const bool finished = false; - /* Fast forward, undo push, then rewind. */ if (is_interactive) { - view3d_smoothview_apply_ex(C, v3d, region_camera, sync_boxview, use_autokey, 1.0f, finished); + view3d_smoothview_apply_with_interp(C, v3d, region_camera, false, 1.0f); } RegionView3D *rv3d = region_camera->regiondata; @@ -134,7 +124,7 @@ void ED_view3d_smooth_view_undo_end(bContext *C, } if (is_interactive) { - view3d_smoothview_apply_ex(C, v3d, region_camera, sync_boxview, use_autokey, 0.0f, finished); + view3d_smoothview_apply_with_interp(C, v3d, region_camera, false, 0.0f); } } @@ -397,110 +387,112 @@ void ED_view3d_smooth_view(bContext *C, } } -static void view3d_smoothview_apply_ex(bContext *C, - View3D *v3d, - ARegion *region, - bool sync_boxview, - bool use_autokey, - const float step, - const bool finished) +/** + * Apply with interpolation, on completion run #view3d_smoothview_apply_and_finish. + */ +static void view3d_smoothview_apply_with_interp( + bContext *C, View3D *v3d, ARegion *region, const bool use_autokey, const float factor) { - wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *rv3d = region->regiondata; struct SmoothView3DStore *sms = rv3d->sms; - /* end timer */ - if (finished) { - wmWindow *win = CTX_wm_window(C); + interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, factor); - /* if we went to camera, store the original */ - if (sms->to_camera) { - rv3d->persp = RV3D_CAMOB; - view3d_smooth_view_state_restore(&sms->org, v3d, rv3d); - } - else { - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + if (sms->use_dyn_ofs) { + view3d_orbit_apply_dyn_ofs( + rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs); + } + else { + interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, factor); + } - view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); + rv3d->dist = interpf(sms->dst.dist, sms->src.dist, factor); + v3d->lens = interpf(sms->dst.lens, sms->src.lens, factor); - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); - } + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + if (use_autokey) { + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); + } - if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { - rv3d->view = sms->org_view; - } + ED_region_tag_redraw(region); +} - MEM_freeN(rv3d->sms); - rv3d->sms = NULL; +/** + * Apply the view-port transformation & free smooth-view related data. + */ +static void view3d_smoothview_apply_and_finish(bContext *C, View3D *v3d, ARegion *region) +{ + wmWindowManager *wm = CTX_wm_manager(C); + RegionView3D *rv3d = region->regiondata; + struct SmoothView3DStore *sms = rv3d->sms; - WM_event_remove_timer(wm, win, rv3d->smooth_timer); - rv3d->smooth_timer = NULL; - rv3d->rflag &= ~RV3D_NAVIGATING; + wmWindow *win = CTX_wm_window(C); - /* Event handling won't know if a UI item has been moved under the pointer. */ - WM_event_add_mousemove(win); + /* if we went to camera, store the original */ + if (sms->to_camera) { + rv3d->persp = RV3D_CAMOB; + view3d_smooth_view_state_restore(&sms->org, v3d, rv3d); } else { - /* ease in/out */ - const float step_inv = 1.0f - step; - - interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step); - - if (sms->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs( - rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs); - } - else { - interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step); - } + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv; - v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; + view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); - const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (use_autokey && ED_screen_animation_playing(wm)) { - ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); - } + ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } - if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) { - view3d_boxview_copy(CTX_wm_area(C), region); + if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) { + rv3d->view = sms->org_view; } + MEM_freeN(rv3d->sms); + rv3d->sms = NULL; + + WM_event_remove_timer(wm, win, rv3d->smooth_timer); + rv3d->smooth_timer = NULL; + rv3d->rflag &= ~RV3D_NAVIGATING; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(win); + /* NOTE: this doesn't work right because the v3d->lens is now used in ortho mode r51636, * when switching camera in quad-view the other ortho views would zoom & reset. * * For now only redraw all regions when smooth-view finishes. */ - if (step >= 1.0f) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); - } - else { - ED_region_tag_redraw(region); - } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); } /* only meant for timer usage */ -static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview) +static void view3d_smoothview_apply_from_timer(bContext *C, View3D *v3d, ARegion *region) { + wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *rv3d = region->regiondata; struct SmoothView3DStore *sms = rv3d->sms; - float step; + float factor; if (sms->time_allowed != 0.0) { - step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); + factor = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); } else { - step = 1.0f; + factor = 1.0f; } - const bool finished = step >= 1.0f; - if (!finished) { - step = (3.0f * step * step - 2.0f * step * step * step); + if (factor >= 1.0f) { + view3d_smoothview_apply_and_finish(C, v3d, region); + } + else { + /* Ease in/out smoothing. */ + factor = (3.0f * factor * factor - 2.0f * factor * factor * factor); + const bool use_autokey = ED_screen_animation_playing(wm); + view3d_smoothview_apply_with_interp(C, v3d, region, use_autokey, factor); + } + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_copy(CTX_wm_area(C), region); } - view3d_smoothview_apply_ex(C, v3d, region, sync_boxview, true, step, finished); } static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -514,7 +506,7 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w return OPERATOR_PASS_THROUGH; } - view3d_smoothview_apply(C, v3d, region, true); + view3d_smoothview_apply_from_timer(C, v3d, region); return OPERATOR_FINISHED; } @@ -524,8 +516,7 @@ void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *regio RegionView3D *rv3d = region->regiondata; if (rv3d && rv3d->sms) { - rv3d->sms->time_allowed = 0.0; /* force finishing */ - view3d_smoothview_apply(C, v3d, region, false); + view3d_smoothview_apply_and_finish(C, v3d, region); /* force update of view matrix so tools that run immediately after * can use them without redrawing first */ diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index 1ccda96fecb..70599c3577c 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -126,19 +126,14 @@ static void constrain_scale_to_boundary(const float numerator, static bool clip_uv_transform_resize(TransInfo *t, float vec[2]) { - /* Check if the current image in UV editor is a tiled image or not. */ - const SpaceImage *sima = t->area->spacedata.first; - const Image *image = sima->image; - const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); /* Stores the coordinates of the closest UDIM tile. * Also acts as an offset to the tile from the origin of UV space. */ float base_offset[2] = {0.0f, 0.0f}; /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ - if (is_tiled_image) { - BKE_image_find_nearest_tile_with_offset(image, t->center_global, base_offset); - } + const SpaceImage *sima = t->area->spacedata.first; + BKE_image_find_nearest_tile_with_offset(sima->image, t->center_global, base_offset); /* Assume no change is required. */ float scale = 1.0f; diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 04a41814b53..8f6ec7bd98f 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -437,19 +437,13 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) static bool clip_uv_transform_translation(TransInfo *t, float vec[2]) { - /* Check if the current image in UV editor is a tiled image or not. */ - const SpaceImage *sima = t->area->spacedata.first; - const Image *image = sima->image; - const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); - /* Stores the coordinates of the closest UDIM tile. * Also acts as an offset to the tile from the origin of UV space. */ float base_offset[2] = {0.0f, 0.0f}; /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ - if (is_tiled_image) { - BKE_image_find_nearest_tile_with_offset(image, t->center_global, base_offset); - } + const SpaceImage *sima = t->area->spacedata.first; + BKE_image_find_nearest_tile_with_offset(sima->image, t->center_global, base_offset); float min[2], max[2]; min[0] = min[1] = FLT_MAX; diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 479214ee2d3..6808f06bdd3 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -498,7 +498,8 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, const bool is_edited = (base->object->mode == OB_MODE_EDIT); const bool is_selectable = (base->flag & BASE_SELECTABLE); /* Get attributes of state. */ - const bool is_in_object_mode = (base_act == NULL) || (base_act->object->mode == OB_MODE_OBJECT); + const bool is_in_object_mode = (base_act == nullptr) || + (base_act->object->mode == OB_MODE_OBJECT); if (is_in_object_mode) { /* Handle target selection options that make sense for object mode. */ diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt index 284b725cdf0..271d05e9c04 100644 --- a/source/blender/editors/undo/CMakeLists.txt +++ b/source/blender/editors/undo/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/guardedalloc + ../../bmesh ) set(SRC diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 04128cf378c..434bfbc64f9 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -14,9 +14,6 @@ struct Scene; struct SpaceImage; struct wmOperatorType; -/* geometric utilities */ -void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len); - /* find nearest */ typedef struct UvNearestHit { diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c index 9a31fd6469d..3877a9bb63b 100644 --- a/source/blender/editors/uvedit/uvedit_islands.c +++ b/source/blender/editors/uvedit/uvedit_islands.c @@ -259,9 +259,8 @@ static float uv_nearest_image_tile_distance(const Image *image, const float coords[2], float nearest_tile_co[2]) { - if (BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co) == -1) { - zero_v2(nearest_tile_co); - } + BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co); + /* Add 0.5 to get tile center coordinates. */ float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]}; add_v2_fl(nearest_tile_center_co, 0.5f); @@ -309,23 +308,8 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2], /* -------------------------------------------------------------------- */ /** \name Calculate UV Islands - * - * \note Currently this is a private API/type, it could be made public. * \{ */ -struct FaceIsland { - struct FaceIsland *next, *prev; - BMFace **faces; - int faces_len; - rctf bounds_rect; - /** - * \note While this is duplicate information, - * it allows islands from multiple meshes to be stored in the same list. - */ - uint cd_loop_uv_offset; - float aspect_y; -}; - struct SharedUVLoopData { uint cd_loop_uv_offset; bool use_seams; @@ -347,14 +331,14 @@ static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, v /** * Calculate islands and add them to \a island_list returning the number of items added. */ -static int bm_mesh_calc_uv_islands(const Scene *scene, - BMesh *bm, - ListBase *island_list, - const bool only_selected_faces, - const bool only_selected_uvs, - const bool use_seams, - const float aspect_y, - const uint cd_loop_uv_offset) +int bm_mesh_calc_uv_islands(const Scene *scene, + BMesh *bm, + ListBase *island_list, + const bool only_selected_faces, + const bool only_selected_uvs, + const bool use_seams, + const float aspect_y, + const uint cd_loop_uv_offset) { int island_added = 0; BM_mesh_elem_table_ensure(bm, BM_FACE); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 74a9989f550..092f0c49d8a 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -189,15 +189,6 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) /** \name Geometric Utilities * \{ */ -void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len) -{ - int i; - for (i = 0; i < len; i++) { - uv[i][0] = uv_orig[i][0] * aspx; - uv[i][1] = uv_orig[i][1] * aspy; - } -} - bool ED_uvedit_minmax_multi( const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]) { @@ -552,11 +543,11 @@ static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool) bool changed = false; /* Loop backwards to simplify logic. */ - int j1 = element_map->totalUVs; + int j1 = element_map->total_uvs; for (int i = element_map->totalIslands - 1; i >= 0; --i) { int j0 = element_map->islandIndices[i]; changed |= uvedit_uv_straighten_elements( - element_map->buf + j0, j1 - j0, cd_loop_uv_offset, tool); + element_map->storage + j0, j1 - j0, cd_loop_uv_offset, tool); j1 = j0; } diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index d59dcb4f4ed..b1ed00e2c57 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -81,6 +81,7 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, typedef enum { UV_SSIM_AREA_UV = 1000, UV_SSIM_AREA_3D, + UV_SSIM_FACE, UV_SSIM_LENGTH_UV, UV_SSIM_LENGTH_3D, UV_SSIM_SIDES, @@ -4638,6 +4639,33 @@ static float get_uv_face_needle(const eUVSelectSimilar type, return result; } +static float get_uv_island_needle(const eUVSelectSimilar type, + const struct FaceIsland *island, + const float ob_m3[3][3], + const int cd_loop_uv_offset) + +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset); + } + break; + case UV_SSIM_AREA_3D: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3); + } + break; + case UV_SSIM_FACE: + return island->faces_len; + default: + BLI_assert_unreachable(); + return false; + } + return result; +} + static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -4969,6 +4997,136 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool uv_island_selected(const Scene *scene, struct FaceIsland *island) +{ + BLI_assert(island && island->faces_len); + return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset); +} + +static int uv_select_similar_island_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__); + int island_list_len = 0; + + const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */ + island_list_len += bm_mesh_calc_uv_islands(scene, + em->bm, + &island_list_ptr[ob_index], + face_selected, + false, + false, + aspect_y, + cd_loop_uv_offset); + } + + struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len, + __func__); + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[index] = island; + if (!uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + int tot_island_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + bool changed = false; + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[tot_island_index++] = island; /* To deallocate later. */ + if (uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (!select) { + continue; + } + bool do_history = false; + for (int j = 0; j < island->faces_len; j++) { + uvedit_face_select_set( + scene, em, island->faces[j], select, do_history, island->cd_loop_uv_offset); + } + changed = true; + } + + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + BLI_assert(tot_island_index == island_list_len); + for (int i = 0; i < island_list_len; i++) { + MEM_SAFE_FREE(island_array[i]->faces); + MEM_SAFE_FREE(island_array[i]); + } + + MEM_SAFE_FREE(island_array); + MEM_SAFE_FREE(island_list_ptr); + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + + return OPERATOR_FINISHED; +} + /* Select similar UV faces/edges/verts based on current selection. */ static int uv_select_similar_exec(bContext *C, wmOperator *op) { @@ -4990,7 +5148,7 @@ static int uv_select_similar_exec(bContext *C, wmOperator *op) return uv_select_similar_face_exec(C, op); } if (selectmode & UV_SELECT_ISLAND) { - // return uv_select_similar_island_exec(C, op); + return uv_select_similar_island_exec(C, op); } return uv_select_similar_vert_exec(C, op); @@ -5011,6 +5169,12 @@ static EnumPropertyItem prop_face_similar_types[] = { {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""}, {0}}; +static EnumPropertyItem prop_island_similar_types[] = { + {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""}, + {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""}, + {UV_SSIM_FACE, "FACE", 0, "Amount of Faces in Island", ""}, + {0}}; + static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, {SIM_CMP_LT, "LESS", 0, "Less", ""}, @@ -5030,6 +5194,9 @@ static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C, if (selectmode & UV_SELECT_FACE) { return prop_face_similar_types; } + if (selectmode & UV_SELECT_ISLAND) { + return prop_island_similar_types; + } } return prop_vert_similar_types; diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 579674930a6..26ed98ba236 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -290,7 +290,7 @@ static void stitch_update_header(StitchStateContainer *ssc, bContext *C) static int getNumOfIslandUvs(UvElementMap *elementMap, int island) { if (island == elementMap->totalIslands - 1) { - return elementMap->totalUVs - elementMap->islandIndices[island]; + return elementMap->total_uvs - elementMap->islandIndices[island]; } return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island]; } @@ -465,7 +465,7 @@ static void stitch_calculate_island_snapping(StitchState *state, angle_to_mat2(rotation_mat, rotation); numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; + element = &state->element_map->storage[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { /* stitchable uvs have already been processed, don't process */ if (!(element->flag & STITCH_PROCESSED)) { @@ -527,8 +527,8 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV); if (ssc->mode == STITCH_VERT) { - index1 = uvfinal_map[element1 - state->element_map->buf]; - index2 = uvfinal_map[element2 - state->element_map->buf]; + index1 = uvfinal_map[element1 - state->element_map->storage]; + index2 = uvfinal_map[element2 - state->element_map->storage]; } else { index1 = edge->uv1; @@ -569,27 +569,17 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data) { - float edgecos = 1.0f, edgesin = 0.0f; - int index; - UvElement *element_iter; float rotation = 0, rotation_neg = 0; int rot_elem = 0, rot_elem_neg = 0; - BMLoop *l; if (element->island == ssc->static_island && !ssc->midpoints) { return; } - l = element->l; - - index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[index]; - + UvElement *element_iter = BM_uv_element_get_head(state->element_map, element); for (; element_iter; element_iter = element_iter->next) { if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - int index_tmp1, index_tmp2; float normal[2]; /* only calculate rotation against static island uv verts */ @@ -597,14 +587,14 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, continue; } - index_tmp1 = element_iter - state->element_map->buf; + int index_tmp1 = element_iter - state->element_map->storage; index_tmp1 = state->map[index_tmp1]; - index_tmp2 = element - state->element_map->buf; + int index_tmp2 = element - state->element_map->storage; index_tmp2 = state->map[index_tmp2]; negate_v2_v2(normal, state->normals + index_tmp2 * 2); - edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); - edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); + float edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); + float edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); if (edgesin > 0.0f) { rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); rot_elem++; @@ -653,9 +643,8 @@ static void state_delete(StitchState *state) if (state->edges) { MEM_freeN(state->edges); } - if (state->stitch_preview) { - stitch_preview_delete(state->stitch_preview); - } + stitch_preview_delete(state->stitch_preview); + state->stitch_preview = NULL; if (state->edge_hash) { BLI_ghash_free(state->edge_hash, NULL, NULL); } @@ -680,10 +669,7 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState * UvEdge *edges = state->edges; const int *map = state->map; UvElementMap *element_map = state->element_map; - UvElement *first_element = element_map->buf; - int i; - - for (i = 0; i < state->total_separate_edges; i++) { + for (int i = 0; i < state->total_separate_edges; i++) { UvEdge *edge = edges + i; if (edge->first) { @@ -696,7 +682,7 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState * UvElement *element2 = state->uvs[edge->uv2]; /* Now iterate through all faces and try to find edges sharing the same vertices */ - UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)]; + UvElement *iter1 = BM_uv_element_get_head(state->element_map, element1); UvEdge *last_set = edge; int elemindex2 = BM_elem_index_get(element2->l->v); @@ -714,8 +700,8 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState * } if (iter2) { - int index1 = map[iter1 - first_element]; - int index2 = map[iter2 - first_element]; + int index1 = map[iter1 - element_map->storage]; + int index2 = map[iter2 - element_map->storage]; UvEdge edgetmp; UvEdge *edge2, *eiter; bool valid = true; @@ -764,15 +750,7 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data) { - int vert_index; - UvElement *element_iter; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - element_iter = state->element_map->vert[vert_index]; - + UvElement *element_iter = BM_uv_element_get_head(state->element_map, element); for (; element_iter; element_iter = element_iter->next) { if (element_iter->separate) { if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) { @@ -853,16 +831,7 @@ static void stitch_validate_uv_stitchability(UvElement *element, return; } - UvElement *element_iter; - int vert_index; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[vert_index]; - + UvElement *element_iter = BM_uv_element_get_head(state->element_map, element); for (; element_iter; element_iter = element_iter->next) { if (element_iter->separate) { if (element_iter == element) { @@ -1177,7 +1146,7 @@ static int stitch_process_data(StitchStateContainer *ssc, int numOfIslandUVs = 0, j; UvElement *element; numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; + element = &state->element_map->storage[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); } @@ -1263,7 +1232,7 @@ static int stitch_process_data(StitchStateContainer *ssc, if (ssc->mode == STITCH_VERT) { final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average"); - uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), + uvfinal_map = MEM_mallocN(state->element_map->total_uvs * sizeof(*uvfinal_map), "stitch_uv_final_map"); } else { @@ -1279,12 +1248,11 @@ static int stitch_process_data(StitchStateContainer *ssc, if (element->flag & STITCH_STITCHABLE) { BMLoop *l; MLoopUV *luv; - UvElement *element_iter; l = element->l; luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - uvfinal_map[element - state->element_map->buf] = i; + uvfinal_map[element - state->element_map->storage] = i; copy_v2_v2(final_position[i].uv, luv->uv); final_position[i].count = 1; @@ -1293,8 +1261,7 @@ static int stitch_process_data(StitchStateContainer *ssc, continue; } - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; - + UvElement *element_iter = state->element_map->vertex[BM_elem_index_get(l->v)]; for (; element_iter; element_iter = element_iter->next) { if (element_iter->separate) { if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { @@ -1542,6 +1509,7 @@ static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int static uint uv_edge_hash(const void *key) { const UvEdge *edge = key; + BLI_assert(edge->uv1 < edge->uv2); return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1)); } @@ -1549,6 +1517,8 @@ static bool uv_edge_compare(const void *a, const void *b) { const UvEdge *edge1 = a; const UvEdge *edge2 = b; + BLI_assert(edge1->uv1 < edge1->uv2); + BLI_assert(edge2->uv1 < edge2->uv2); if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { return 0; @@ -1588,13 +1558,8 @@ static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_sele /* Select all common uvs */ static void stitch_select_uv(UvElement *element, StitchState *state, int always_select) { - BMLoop *l; - UvElement *element_iter; UvElement **selection_stack = (UvElement **)state->selection_stack; - - l = element->l; - - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; + UvElement *element_iter = BM_uv_element_get_head(state->element_map, element); /* first deselect all common uvs */ for (; element_iter; element_iter = element_iter->next) { if (element_iter->separate) { @@ -1850,8 +1815,8 @@ static UvEdge *uv_edge_get(BMLoop *l, StitchState *state) UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l); UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next); - int uv1 = state->map[element1 - state->element_map->buf]; - int uv2 = state->map[element2 - state->element_map->buf]; + int uv1 = state->map[element1 - state->element_map->storage]; + int uv2 = state->map[element2 - state->element_map->storage]; if (uv1 < uv2) { tmp_edge.uv1 = uv1; @@ -1878,7 +1843,6 @@ static StitchState *stitch_init(bContext *C, int total_edges; /* maps uvelements to their first coincident uv */ int *map; - int counter = 0, i; BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1913,45 +1877,39 @@ static StitchState *stitch_init(bContext *C, ED_uvedit_get_aspect(obedit, &aspx, &aspy); state->aspect = aspx / aspy; - /* Count 'unique' uvs */ - for (i = 0; i < state->element_map->totalUVs; i++) { - if (state->element_map->buf[i].separate) { - counter++; - } - } + int unique_uvs = state->element_map->total_unique_uvs; + state->total_separate_uvs = unique_uvs; - /* explicitly set preview to NULL, - * to avoid deleting an invalid pointer on stitch_process_data */ - state->stitch_preview = NULL; /* Allocate the unique uv buffers */ - state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs"); + state->uvs = MEM_mallocN(sizeof(*state->uvs) * unique_uvs, "uv_stitch_unique_uvs"); /* internal uvs need no normals but it is hard and slow to keep a map of - * normals only for boundary uvs, so allocating for all uvs */ - state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals"); - state->total_separate_uvs = counter; - state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, + * normals only for boundary uvs, so allocating for all uvs. + * Times 2 because each `float[2]` is stored as `{n[2 * i], n[2*i + 1]}`. */ + state->normals = MEM_callocN(sizeof(*state->normals) * 2 * unique_uvs, "uv_stitch_normals"); + state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->total_uvs, "uv_stitch_unique_map"); /* Allocate the edge stack */ edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); - all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges"); + all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->total_uvs, "ssc_edges"); + BLI_assert(!state->stitch_preview); /* Paranoia. */ if (!state->uvs || !map || !edge_hash || !all_edges) { state_delete(state); return NULL; } - /* So that we can use this as index for the UvElements */ - counter = -1; + /* Index for the UvElements. */ + int counter = -1; /* initialize the unique UVs and map */ - for (i = 0; i < em->bm->totvert; i++) { - UvElement *element = state->element_map->vert[i]; + for (int i = 0; i < em->bm->totvert; i++) { + UvElement *element = state->element_map->vertex[i]; for (; element; element = element->next) { if (element->separate) { counter++; state->uvs[counter] = element; } /* Pointer arithmetic to the rescue, as always :). */ - map[element - state->element_map->buf] = counter; + map[element - state->element_map->storage] = counter; } } @@ -1965,13 +1923,13 @@ static StitchState *stitch_init(bContext *C, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { UvElement *element = BM_uv_element_get(state->element_map, efa, l); - int offset1, itmp1 = element - state->element_map->buf; - int offset2, - itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; + int itmp1 = element - state->element_map->storage; + int itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - + state->element_map->storage; UvEdge *edge; - offset1 = map[itmp1]; - offset2 = map[itmp2]; + int offset1 = map[itmp1]; + int offset2 = map[itmp2]; all_edges[counter].next = NULL; all_edges[counter].first = NULL; @@ -2012,7 +1970,7 @@ static StitchState *stitch_init(bContext *C, state->total_separate_edges = total_edges; /* fill the edges with data */ - i = 0; + int i = 0; GHASH_ITER (gh_iter, edge_hash) { edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); } @@ -2091,13 +2049,13 @@ static StitchState *stitch_init(bContext *C, efa = BM_face_at_index(em->bm, faceIndex); element = BM_uv_element_get( state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); - uv1 = map[element - state->element_map->buf]; + uv1 = map[element - state->element_map->storage]; element = BM_uv_element_get( state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len)); - uv2 = map[element - state->element_map->buf]; + uv2 = map[element - state->element_map->storage]; if (uv1 < uv2) { tmp_edge.uv1 = uv1; diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp index b26a833b32e..d918cfec2ae 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp @@ -398,7 +398,7 @@ void TVertex::setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming) void TVertex::Replace(ViewEdge *iOld, ViewEdge *iNew) { - // theoritically, we only replace edges for which this + // theoretically, we only replace edges for which this // view vertex is the B vertex if ((iOld == _FrontEdgeA.first) && (_FrontEdgeA.first->B() == this)) { _FrontEdgeA.first = iNew; diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index da83d9e8957..0f06890cbfa 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -27,7 +27,7 @@ set(SRC intern/reverse_uv_sampler.cc intern/set_curve_type.cc intern/subdivide_curves.cc - intern/uv_parametrizer.c + intern/uv_parametrizer.cc GEO_add_curves_on_mesh.hh GEO_fillet_curves.hh diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc index 7184d774a22..299040d4d32 100644 --- a/source/blender/geometry/intern/add_curves_on_mesh.cc +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BLI_length_parameterize.hh" +#include "BLI_task.hh" #include "BKE_attribute_math.hh" #include "BKE_mesh_sample.hh" @@ -102,8 +103,8 @@ void interpolate_from_neighbors(const Span<NeighborCurves> neighbors_per_curve, } } } + mixer.finalize(range); }); - mixer.finalize(); } static void interpolate_position_without_interpolation( diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc index 40ee2488a4b..92609a45bdc 100644 --- a/source/blender/geometry/intern/set_curve_type.cc +++ b/source/blender/geometry/intern/set_curve_type.cc @@ -286,42 +286,6 @@ static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan< }); } -struct GenericAttributes : NonCopyable, NonMovable { - Vector<GSpan> src; - Vector<GMutableSpan> dst; - - Vector<bke::GSpanAttributeWriter> attributes; -}; - -static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes, - bke::MutableAttributeAccessor &dst_attributes, - GenericAttributes &attributes) -{ - src_attributes.for_all( - [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { - if (meta_data.domain != ATTR_DOMAIN_POINT) { - /* Curve domain attributes are all copied directly to the result in one step. */ - return true; - } - if (src_attributes.is_builtin(id)) { - if (!(id.is_named() && ELEM(id, "tilt", "radius"))) { - return true; - } - } - - GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT); - BLI_assert(src_attribute); - attributes.src.append(src_attribute.get_internal_span()); - - bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span( - id, ATTR_DOMAIN_POINT, meta_data.data_type); - attributes.dst.append(dst_attribute.span); - attributes.attributes.append(std::move(dst_attribute)); - - return true; - }); -} - static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &src_curves, const IndexMask selection) { @@ -347,8 +311,16 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s const bke::AttributeAccessor src_attributes = src_curves.attributes(); bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); - GenericAttributes attributes; - retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); + Vector<bke::AttributeTransferData> generic_attributes = bke::retrieve_attributes_for_transfer( + src_attributes, + dst_attributes, + ATTR_DOMAIN_MASK_POINT, + {"position", + "handle_type_left", + "handle_type_right", + "handle_right", + "handle_left", + "nurbs_weight"}); MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write(); @@ -373,9 +345,9 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s } }); - for (const int i : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { bke::curves::copy_point_data( - src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + src_curves, dst_curves, selection, attribute.src, attribute.dst.span); } }; @@ -384,9 +356,9 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l); bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r); dst_curves.calculate_bezier_auto_handles(); - for (const int i : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { bke::curves::copy_point_data( - src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + src_curves, dst_curves, selection, attribute.src, attribute.dst.span); } }; @@ -404,9 +376,9 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s dst_curves.calculate_bezier_auto_handles(); - for (const int i : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { bke::curves::copy_point_data( - src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]); + src_curves, dst_curves, selection, attribute.src, attribute.dst.span); } }; @@ -445,14 +417,14 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s } }); - for (const int i_attribute : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i : selection.slice(range)) { const IndexRange src_points = src_curves.points_for_curve(i); const IndexRange dst_points = dst_curves.points_for_curve(i); - nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points), + nurbs_to_bezier_assign(attribute.src.slice(src_points), KnotsMode(src_knot_modes[i]), - attributes.dst[i_attribute].slice(dst_points)); + attribute.dst.span.slice(dst_points)); } }); } @@ -469,13 +441,13 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert( src_curves.curves_range()); - for (const int i : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { bke::curves::copy_point_data( - src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); + src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); } - for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { - attribute.finish(); + for (bke::AttributeTransferData &attribute : generic_attributes) { + attribute.dst.finish(); } return dst_curves; @@ -504,8 +476,16 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr const bke::AttributeAccessor src_attributes = src_curves.attributes(); bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); - GenericAttributes attributes; - retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); + Vector<bke::AttributeTransferData> generic_attributes = bke::retrieve_attributes_for_transfer( + src_attributes, + dst_attributes, + ATTR_DOMAIN_MASK_POINT, + {"position", + "handle_type_left", + "handle_type_right", + "handle_right", + "handle_left", + "nurbs_weight"}); MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); @@ -529,13 +509,13 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr } }); - for (const int i_attribute : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i : selection.slice(range)) { const IndexRange src_points = src_curves.points_for_curve(i); const IndexRange dst_points = dst_curves.points_for_curve(i); - bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points), - attributes.dst[i_attribute].slice(dst_points)); + bezier_generic_to_nurbs(attribute.src.slice(src_points), + attribute.dst.span.slice(dst_points)); } }); } @@ -563,12 +543,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr }); } - for (const int i_attribute : attributes.src.index_range()) { - bke::curves::copy_point_data(src_curves, - dst_curves, - selection, - attributes.src[i_attribute], - attributes.dst[i_attribute]); + for (bke::AttributeTransferData &attribute : generic_attributes) { + bke::curves::copy_point_data( + src_curves, dst_curves, selection, attribute.src, attribute.dst.span); } }; @@ -591,13 +568,13 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr } }); - for (const int i_attribute : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i : selection.slice(range)) { const IndexRange src_points = src_curves.points_for_curve(i); const IndexRange dst_points = dst_curves.points_for_curve(i); - bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points), - attributes.dst[i_attribute].slice(dst_points)); + bezier_generic_to_nurbs(attribute.src.slice(src_points), + attribute.dst.span.slice(dst_points)); } }); } @@ -614,12 +591,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr dst_curves.nurbs_weights_for_write()); } - for (const int i_attribute : attributes.src.index_range()) { - bke::curves::copy_point_data(src_curves, - dst_curves, - selection, - attributes.src[i_attribute], - attributes.dst[i_attribute]); + for (bke::AttributeTransferData &attribute : generic_attributes) { + bke::curves::copy_point_data( + src_curves, dst_curves, selection, attribute.src, attribute.dst.span); } }; @@ -634,13 +608,13 @@ static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &sr const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert( src_curves.curves_range()); - for (const int i : attributes.src.index_range()) { + for (bke::AttributeTransferData &attribute : generic_attributes) { bke::curves::copy_point_data( - src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); + src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); } - for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { - attribute.finish(); + for (bke::AttributeTransferData &attribute : generic_attributes) { + attribute.dst.finish(); } return dst_curves; diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.cc index 38924c718c3..ae2794bf9bc 100644 --- a/source/blender/geometry/intern/uv_parametrizer.c +++ b/source/blender/geometry/intern/uv_parametrizer.cc @@ -51,15 +51,13 @@ typedef struct PVert { union PVertUnion { PHashKey key; /* Construct. */ int id; /* ABF/LSCM matrix index. */ - float distortion; /* Area smoothing. */ HeapNode *heaplink; /* Edge collapsing. */ } u; struct PEdge *edge; float co[3]; float uv[2]; - uchar flag; - + uint flag; } PVert; typedef struct PEdge { @@ -77,8 +75,7 @@ typedef struct PEdge { struct PEdge *next; struct PFace *face; float *orig_uv, old_uv[2]; - ushort flag; - + uint flag; } PEdge; typedef struct PFace { @@ -153,14 +150,9 @@ typedef struct PChart { } pack; } u; - uchar flag; - ParamHandle *handle; + bool has_pins; } PChart; -enum PChartFlag { - PCHART_HAS_PINS = 1, -}; - enum PHandleState { PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED, @@ -225,8 +217,10 @@ static PHash *phash_new(PHashLink **list, int sizehint) static void phash_delete(PHash *ph) { - MEM_freeN(ph->buckets); - MEM_freeN(ph); + if (ph) { + MEM_SAFE_FREE(ph->buckets); + } + MEM_SAFE_FREE(ph); } static int phash_size(PHash *ph) @@ -670,9 +664,9 @@ static PVert *p_vert_lookup(ParamHandle *handle, PHashKey key, const float co[3] return p_vert_add(handle, key, co, e); } -static PVert *p_vert_copy(PChart *chart, PVert *v) +static PVert *p_vert_copy(ParamHandle *handle, PVert *v) { - PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv)); + PVert *nv = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*nv)); copy_v3_v3(nv->co, v->co); nv->uv[0] = v->uv[0]; @@ -727,20 +721,6 @@ static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, in return false; } -static PChart *p_chart_new(ParamHandle *handle) -{ - PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); - chart->handle = handle; - - return chart; -} - -static void p_chart_delete(PChart *chart) -{ - /* the actual links are free by memarena */ - MEM_freeN(chart); -} - static bool p_edge_implicit_seam(PEdge *e, PEdge *ep) { float *uv1, *uv2, *uvp1, *uvp2; @@ -850,8 +830,8 @@ static bool p_edge_connect_pair(ParamHandle *handle, static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs) { - PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), - "Pstackbase"); + PEdge **stackbase = (PEdge **)MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces), + "Pstackbase"); PEdge **stack = stackbase; PFace *f, *first; PEdge *e, *e1, *e2; @@ -893,19 +873,19 @@ static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs) ncharts++; } - MEM_freeN(stackbase); + MEM_SAFE_FREE(stackbase); return ncharts; } -static void p_split_vert(PChart *chart, PEdge *e) +static void p_split_vert(ParamHandle *handle, PChart *chart, PEdge *e) { PEdge *we, *lastwe = NULL; PVert *v = e->vert; bool copy = true; if (e->flag & PEDGE_PIN) { - chart->flag |= PCHART_HAS_PINS; + chart->has_pins = true; } if (e->flag & PEDGE_VERTEX_SPLIT) { @@ -938,7 +918,7 @@ static void p_split_vert(PChart *chart, PEdge *e) if (copy) { /* not found, copying */ v->flag |= PVERT_SPLIT; - v = p_vert_copy(chart, v); + v = p_vert_copy(handle, v); v->flag |= PVERT_SPLIT; v->nextlink = chart->verts; @@ -957,20 +937,18 @@ static void p_split_vert(PChart *chart, PEdge *e) static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts) { - PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart; - PFace *f, *nextf; - int i; + PChart **charts = (PChart **)MEM_callocN(sizeof(*charts) * ncharts, "PCharts"); - for (i = 0; i < ncharts; i++) { - charts[i] = p_chart_new(handle); + for (int i = 0; i < ncharts; i++) { + charts[i] = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); } - f = chart->faces; + PFace *f = chart->faces; while (f) { PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; - nextf = f->nextlink; + PFace *nextf = f->nextlink; - nchart = charts[f->u.chart]; + PChart *nchart = charts[f->u.chart]; f->nextlink = nchart->faces; nchart->faces = f; @@ -984,9 +962,9 @@ static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts) nchart->nfaces++; nchart->nedges += 3; - p_split_vert(nchart, e1); - p_split_vert(nchart, e2); - p_split_vert(nchart, e3); + p_split_vert(handle, nchart, e1); + p_split_vert(handle, nchart, e2); + p_split_vert(handle, nchart, e3); f = nextf; } @@ -1086,9 +1064,9 @@ static PFace *p_face_add_construct(ParamHandle *handle, return f; } -static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3) +static PFace *p_face_add_fill(ParamHandle *handle, PChart *chart, PVert *v1, PVert *v2, PVert *v3) { - PFace *f = p_face_add(chart->handle); + PFace *f = p_face_add(handle); PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; e1->vert = v1; @@ -1202,7 +1180,7 @@ static float p_edge_boundary_angle(PEdge *e) return angle; } -static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) +static void p_chart_fill_boundary(ParamHandle *handle, PChart *chart, PEdge *be, int nedges) { PEdge *e, *e1, *e2; @@ -1243,7 +1221,7 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) e->flag |= PEDGE_FILLED; e1->flag |= PEDGE_FILLED; - f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert); + f = p_face_add_fill(handle, chart, e->vert, e1->vert, e2->vert); f->flag |= PFACE_FILLED; ne = f->edge->next->next; @@ -1279,7 +1257,7 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) BLI_heap_free(heap, NULL); } -static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) +static void p_chart_fill_boundaries(ParamHandle *handle, PChart *chart, PEdge *outer) { PEdge *e, *be; /* *enext - as yet unused */ int nedges; @@ -1300,7 +1278,7 @@ static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) } while (be != e); if (e != outer) { - p_chart_fill_boundary(chart, e, nedges); + p_chart_fill_boundary(handle, chart, e, nedges); } } } @@ -2309,7 +2287,7 @@ static void p_abf_setup_system(PAbfSystem *sys) sys->lambdaPlanar = (float *)MEM_callocN(sizeof(float) * sys->ninterior, "ABFlamdaplane"); sys->lambdaLength = (float *)MEM_mallocN(sizeof(float) * sys->ninterior, "ABFlambdalen"); - sys->J2dt = MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt"); + sys->J2dt = static_cast<float(*)[3]>(MEM_mallocN(sizeof(float) * sys->nangles * 3, "ABFj2dt")); sys->bstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFbstar"); sys->dstar = (float *)MEM_mallocN(sizeof(float) * sys->nfaces, "ABFdstar"); @@ -2808,7 +2786,7 @@ static bool p_chart_abf_solve(PChart *chart) } } - chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha); + chart->u.lscm.abf_alpha = (float *)MEM_dupallocN(sys.alpha); p_abf_free_system(&sys); return true; @@ -3266,13 +3244,11 @@ static void p_chart_lscm_transform_single_pin(PChart *chart) static void p_chart_lscm_end(PChart *chart) { - if (chart->u.lscm.context) { - EIG_linear_solver_delete(chart->u.lscm.context); - } + EIG_linear_solver_delete(chart->u.lscm.context); + chart->u.lscm.context = NULL; MEM_SAFE_FREE(chart->u.lscm.abf_alpha); - chart->u.lscm.context = NULL; chart->u.lscm.pin1 = NULL; chart->u.lscm.pin2 = NULL; chart->u.lscm.single_pin = NULL; @@ -3519,8 +3495,8 @@ static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, *r_nverts = npoints; *r_right = ulen - 1; - MEM_freeN(U); - MEM_freeN(L); + MEM_SAFE_FREE(U); + MEM_SAFE_FREE(L); return true; } @@ -3566,7 +3542,7 @@ static float p_chart_minimum_area_angle(PChart *chart) } /* find left/top/right/bottom points, and compute angle for each point */ - angles = MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles"); + angles = (float *)MEM_mallocN(sizeof(float) * npoints, "PMinAreaAngles"); i_min = i_max = 0; miny = 1e10; @@ -3668,8 +3644,8 @@ static float p_chart_minimum_area_angle(PChart *chart) minangle -= (float)M_PI_2; } - MEM_freeN(angles); - MEM_freeN(points); + MEM_SAFE_FREE(angles); + MEM_SAFE_FREE(points); return minangle; } @@ -3690,7 +3666,8 @@ static void p_chart_rotate_minimum_area(PChart *chart) static void p_chart_rotate_fit_aabb(PChart *chart) { - float(*points)[2] = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); + float(*points)[2] = static_cast<float(*)[2]>( + MEM_mallocN(sizeof(*points) * chart->nverts, __func__)); p_chart_uv_to_array(chart, points); @@ -3709,8 +3686,8 @@ static void p_chart_rotate_fit_aabb(PChart *chart) ParamHandle *GEO_uv_parametrizer_construct_begin(void) { - ParamHandle *handle = MEM_callocN(sizeof(*handle), "ParamHandle"); - handle->construction_chart = p_chart_new(handle); + ParamHandle *handle = (ParamHandle *)MEM_callocN(sizeof(*handle), "ParamHandle"); + handle->construction_chart = (PChart *)MEM_callocN(sizeof(PChart), "PChart"); handle->state = PHANDLE_STATE_ALLOCATED; handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena"); handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena"); @@ -3733,12 +3710,10 @@ void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float as void GEO_uv_parametrizer_delete(ParamHandle *phandle) { - int i; - param_assert(ELEM(phandle->state, PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED)); - for (i = 0; i < phandle->ncharts; i++) { - p_chart_delete(phandle->charts[i]); + for (int i = 0; i < phandle->ncharts; i++) { + MEM_SAFE_FREE(phandle->charts[i]); } MEM_SAFE_FREE(phandle->charts); @@ -3748,17 +3723,19 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle) phandle->pin_hash = NULL; } - if (phandle->construction_chart) { - p_chart_delete(phandle->construction_chart); + MEM_SAFE_FREE(phandle->construction_chart); - phash_delete(phandle->hash_verts); - phash_delete(phandle->hash_edges); - phash_delete(phandle->hash_faces); - } + phash_delete(phandle->hash_verts); + phash_delete(phandle->hash_edges); + phash_delete(phandle->hash_faces); BLI_memarena_free(phandle->arena); BLI_memarena_free(phandle->polyfill_arena); BLI_heap_free(phandle->polyfill_heap, NULL); + + BLI_rng_free(phandle->rng); + phandle->rng = NULL; + MEM_freeN(phandle); } @@ -3782,7 +3759,8 @@ ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const return bmvertindex; /* No verts pinned. */ } - GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex)); + const GeoUVPinIndex *pinuvlist = (const GeoUVPinIndex *)BLI_ghash_lookup( + handle->pin_hash, POINTER_FROM_INT(bmvertindex)); if (!pinuvlist) { return bmvertindex; /* Vert not pinned. */ } @@ -3804,7 +3782,7 @@ ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2]) { - GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv)); + GeoUVPinIndex *pinuv = (GeoUVPinIndex *)BLI_memarena_alloc(handle->arena, sizeof(*pinuv)); pinuv->next = NULL; copy_v2_v2(pinuv->uv, uv); pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++); @@ -3817,7 +3795,8 @@ void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const handle->pin_hash = BLI_ghash_int_new("uv pin reindex"); } - GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex)); + GeoUVPinIndex *pinuvlist = (GeoUVPinIndex *)BLI_ghash_lookup(handle->pin_hash, + POINTER_FROM_INT(bmvertindex)); if (!pinuvlist) { BLI_ghash_insert( handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv)); @@ -3849,8 +3828,10 @@ static void p_add_ngon(ParamHandle *handle, MemArena *arena = handle->polyfill_arena; Heap *heap = handle->polyfill_heap; uint nfilltri = nverts - 2; - uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri); - float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts); + uint(*tris)[3] = static_cast<uint(*)[3]>( + BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri)); + float(*projverts)[2] = static_cast<float(*)[2]>( + BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts)); /* Calc normal, flipped: to get a positive 2d cross product. */ float normal[3]; @@ -3957,8 +3938,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs); phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); - p_chart_delete(phandle->construction_chart); - phandle->construction_chart = NULL; + MEM_SAFE_FREE(phandle->construction_chart); phash_delete(phandle->hash_verts); phash_delete(phandle->hash_edges); @@ -3972,7 +3952,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, p_chart_boundaries(chart, &outer); if (!topology_from_uvs && chart->nboundaries == 0) { - p_chart_delete(chart); + MEM_SAFE_FREE(chart); if (count_fail != NULL) { *count_fail += 1; } @@ -3983,7 +3963,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, j++; if (fill && (chart->nboundaries > 1)) { - p_chart_fill_boundaries(chart, outer); + p_chart_fill_boundaries(phandle, chart, outer); } for (v = chart->verts; v; v = v->nextlink) { @@ -4025,7 +4005,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in if (chart->u.lscm.context) { const bool result = p_chart_lscm_solve(phandle, chart); - if (result && !(chart->flag & PCHART_HAS_PINS)) { + if (result && !chart->has_pins) { p_chart_rotate_minimum_area(chart); } else if (result && chart->u.lscm.single_pin) { @@ -4033,7 +4013,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in p_chart_lscm_transform_single_pin(chart); } - if (!result || !(chart->flag & PCHART_HAS_PINS)) { + if (!result || !chart->has_pins) { p_chart_lscm_end(chart); } @@ -4053,11 +4033,9 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in void GEO_uv_parametrizer_lscm_end(ParamHandle *phandle) { - int i; - - param_assert(phandle->state == PHANDLE_STATE_LSCM); + BLI_assert(phandle->state == PHANDLE_STATE_LSCM); - for (i = 0; i < phandle->ncharts; i++) { + for (int i = 0; i < phandle->ncharts; i++) { p_chart_lscm_end(phandle->charts[i]); #if 0 p_chart_complexify(phandle->charts[i]); @@ -4119,9 +4097,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle) { param_assert(phandle->state == PHANDLE_STATE_STRETCH); phandle->state = PHANDLE_STATE_CONSTRUCTED; - - BLI_rng_free(phandle->rng); - phandle->rng = NULL; } /* don't pack, just rotate (used for better packing) */ @@ -4133,7 +4108,7 @@ static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pi for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } @@ -4169,12 +4144,12 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, } /* we may not use all these boxes */ - boxarray = MEM_mallocN(handle->ncharts * sizeof(BoxPack), "BoxPack box"); + boxarray = (BoxPack *)MEM_mallocN(handle->ncharts * sizeof(BoxPack), "BoxPack box"); for (i = 0; i < handle->ncharts; i++) { chart = handle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { unpacked++; continue; } @@ -4190,7 +4165,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, box->w = chart->u.pack.size[0] + trans[0]; box->h = chart->u.pack.size[1] + trans[1]; - box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */ + box->index = i; /* Warning this index skips chart->has_pins boxes. */ if (margin > 0.0f) { area += (double)sqrtf(box->w * box->h); @@ -4207,7 +4182,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, for (i = 0; i < handle->ncharts; i++) { chart = handle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { unpacked++; continue; } @@ -4239,7 +4214,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, p_chart_uv_translate(chart, trans); p_chart_uv_scale(chart, scale); } - MEM_freeN(boxarray); + MEM_SAFE_FREE(boxarray); if (handle->aspx != handle->aspy) { GEO_uv_parametrizer_scale(handle, handle->aspx, handle->aspy); @@ -4264,7 +4239,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } @@ -4367,7 +4342,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c index 5033e67d52e..68a4b39a21e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c @@ -270,7 +270,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, } static void segment_list_item(struct uiList *UNUSED(ui_list), - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(idataptr), struct PointerRNA *itemptr, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c index f492e9ee044..74b7efb1d04 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c @@ -202,7 +202,6 @@ static void updateDepsgraph(GpencilModifierData *md, CustomData_MeshMasks mask = {0}; if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) { - mask.vmask |= CD_MASK_NORMAL; mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; } @@ -225,7 +224,7 @@ static void updateDepsgraph(GpencilModifierData *md, ctx->node, &mmd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); } } - DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Shrinkwrap Modifier"); } static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData) diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 224146d0032..63433113822 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -366,8 +366,9 @@ typedef struct LineartData { /* Keep an copy of these data so when line art is running it's self-contained. */ bool cam_is_persp; - bool cam_is_persp_secondary; /* "Secondary" ones are from viewing camera (as opposed to shadow - camera), during shadow calculation. */ + /* "Secondary" ones are from viewing camera + * (as opposed to shadow camera), during shadow calculation. */ + bool cam_is_persp_secondary; float cam_obmat[4][4]; float cam_obmat_secondary[4][4]; double camera_pos[3]; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c index 24762ce921d..bf42677d79c 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c @@ -482,7 +482,7 @@ static void lineart_shadow_create_shadow_edge_array(LineartData *ld, * This process is repeated on each existing segments of the shadow edge (#e), which ensures they * all have been tested for closest segments after cutting. And in the diagram it's clear that the * left/right side of cuts are likely to be discontinuous, each cut's left side designates the - * right side of the last segment, and vise versa. */ + * right side of the last segment, and vice-versa. */ static void lineart_shadow_edge_cut(LineartData *ld, LineartShadowEdge *e, double start, diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5e97909a2b8..91819a8806b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -190,8 +190,8 @@ set(OPENGL_SRC set(METAL_SRC metal/mtl_backend.mm - metal/mtl_context.mm metal/mtl_command_buffer.mm + metal/mtl_context.mm metal/mtl_debug.mm metal/mtl_framebuffer.mm metal/mtl_memory.mm @@ -454,8 +454,10 @@ list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR}) set(SRC_SHADER_CREATE_INFOS ../draw/engines/basic/shaders/infos/basic_depth_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh @@ -468,8 +470,8 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/overlay/shaders/infos/overlay_grid_info.hh ../draw/engines/overlay/shaders/infos/overlay_outline_info.hh ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh - ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh ../draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh + ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh ../draw/engines/select/shaders/infos/select_id_info.hh @@ -591,9 +593,9 @@ if(WITH_GPU_BUILDTIME_SHADER_BUILDER) endif() target_link_libraries(shader_builder PUBLIC + bf_blenlib bf_gpu bf_intern_clog - bf_blenlib bf_intern_ghost ${PLATFORM_LINKLIBS} ) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 7fad8dd23be..7ef2d81ac31 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -14,6 +14,7 @@ #include "GPU_index_buffer.h" #include "GPU_shader.h" +#include "GPU_storage_buffer.h" #include "GPU_uniform_buffer.h" #include "GPU_vertex_buffer.h" @@ -171,7 +172,13 @@ void GPU_batch_draw_instanced(GPUBatch *batch, int i_count); /** * This does not bind/unbind shader and does not call GPU_matrix_bind(). */ -void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count); +void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count); + +/** + * Issue a draw call using GPU computed arguments. The argument are expected to be valid for the + * type of geometry drawn (index or non-indexed). + */ +void GPU_batch_draw_indirect(GPUBatch *batch, GPUStorageBuf *indirect_buf); #if 0 /* future plans */ diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 89473ac0fe0..6dc49ff494d 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -22,6 +22,7 @@ struct CCGKey; struct DMFlagMat; struct GSet; struct TableGSet; +struct Mesh; struct MLoop; struct MLoopCol; struct MLoopTri; @@ -46,14 +47,12 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; * * Threaded: do not call any functions that use OpenGL calls! */ -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly, - const struct MLoop *mloop, +GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct Mesh *mesh, + const struct MVert *vertices, const struct MLoopTri *looptri, - const struct MVert *mvert, - const int *face_indices, const int *sculpt_face_sets, - int face_indices_len, - const struct Mesh *mesh); + const int *face_indices, + int face_indices_len); /** * Threaded: do not call any functions that use OpenGL calls! @@ -91,9 +90,8 @@ enum { */ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPU_PBVH_Buffers *buffers, + const struct Mesh *mesh, const struct MVert *mvert, - const CustomData *vdata, - const CustomData *ldata, const float *vmask, const int *sculpt_face_sets, const int face_sets_color_seed, diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 3ca465fa57a..1ab06f3369d 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -121,6 +121,7 @@ typedef struct GPUCodegenOutput { char *surface; char *volume; char *thickness; + char *composite; char *material_functions; GPUShaderCreateInfo *create_info; @@ -166,10 +167,6 @@ bool GPU_stack_link(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out, ...); -GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat, - struct bNode *node, - struct GPUNodeStack *stack, - int index); void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link); void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link); @@ -178,6 +175,8 @@ void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link); void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash); +void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link); + /** * Wrap a part of the material graph into a function. You need then need to call the function by * using something like #GPU_differentiate_float_function. @@ -218,6 +217,7 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, void *thunk); void GPU_material_compile(GPUMaterial *mat); +void GPU_material_free_single(GPUMaterial *material); void GPU_material_free(struct ListBase *gpumaterial); void GPU_material_acquire(GPUMaterial *mat); @@ -319,6 +319,16 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info); void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, GPUUniformAttrList *src); void GPU_uniform_attr_list_free(GPUUniformAttrList *set); +/* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and + * linking the necessary GPU material nodes. */ +typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material); + +/* Construct a GPU material from a set of callbacks. See the callback types for more information. + * The given thunk will be passed as the first parameter of each callback. */ +GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, + GPUCodegenCallbackFn generate_code_function_cb, + void *thunk); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3460d33fe68..c154f1adc8b 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -177,7 +177,9 @@ void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, fl void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]); void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]); void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]); +void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]); void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]); +void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]); void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]); void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 5bd20b7be98..6e31b1b69f6 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -331,6 +331,7 @@ int GPU_texture_orig_width(const GPUTexture *tex); int GPU_texture_orig_height(const GPUTexture *tex); void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h); eGPUTextureFormat GPU_texture_format(const GPUTexture *tex); +const char *GPU_texture_format_description(eGPUTextureFormat texture_format); bool GPU_texture_array(const GPUTexture *tex); bool GPU_texture_cube(const GPUTexture *tex); bool GPU_texture_depth(const GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 1b34b6e6c69..0b47a7b2952 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -270,6 +270,15 @@ void GPU_batch_draw_advanced( batch->draw(v_first, v_count, i_first, i_count); } +void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf) +{ + BLI_assert(Context::get()->shader != nullptr); + BLI_assert(indirect_buf != nullptr); + Batch *batch = static_cast<Batch *>(gpu_batch); + + batch->draw_indirect(indirect_buf); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index 23052f601d2..8ca19884fd7 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -29,6 +29,7 @@ class Batch : public GPUBatch { virtual ~Batch() = default; virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; + virtual void draw_indirect(GPUStorageBuf *indirect_buf) = 0; /* Convenience casts. */ IndexBuf *elem_() const diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 14bbd82c282..2a0f624ac45 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -221,9 +221,8 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPU_PBVH_Buffers *buffers, + const Mesh *mesh, const MVert *mvert, - const CustomData *vdata, - const CustomData *ldata, const float *vmask, const int *sculpt_face_sets, int face_sets_color_seed, @@ -234,23 +233,20 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPUAttrRef vcol_refs[MAX_GPU_ATTR]; GPUAttrRef cd_uvs[MAX_GPU_ATTR]; - Mesh me_query; - BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id); - - CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id); - eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) : + const CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&mesh->id); + eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&mesh->id, actcol) : ATTR_DOMAIN_AUTO; - CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id); + const CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&mesh->id); int totcol; if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) { totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL, - vdata, + &mesh->vdata, NULL, - ldata, + &mesh->ldata, NULL, vcol_refs, vbo_id->active_attrs_only, @@ -267,14 +263,14 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, CD_MASK_MLOOPUV, NULL, NULL, - ldata, + &mesh->ldata, NULL, cd_uvs, vbo_id->active_attrs_only, CD_MLOOPUV, ATTR_DOMAIN_CORNER, - get_active_layer(ldata, CD_MLOOPUV), - get_render_layer(ldata, CD_MLOOPUV)); + get_active_layer(&mesh->ldata, CD_MLOOPUV), + get_render_layer(&mesh->ldata, CD_MLOOPUV)); const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; const bool show_face_sets = sculpt_face_sets && @@ -308,7 +304,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step); GPUAttrRef *ref = cd_uvs + uv_i; - CustomDataLayer *layer = ldata->layers + ref->layer_idx; + CustomDataLayer *layer = mesh->ldata.layers + ref->layer_idx; MLoopUV *muv = layer->data; for (uint i = 0; i < buffers->face_indices_len; i++) { @@ -334,7 +330,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, MLoopCol *mcol = NULL; GPUAttrRef *ref = vcol_refs + col_i; - const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata; + const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? &mesh->vdata : &mesh->ldata; CustomDataLayer *layer = cdata->layers + ref->layer_idx; bool color_loops = ref->domain == ATTR_DOMAIN_CORNER; @@ -457,19 +453,20 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, buffers->mvert = mvert; } -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, - const MLoop *mloop, +GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, + const MVert *vertices, const MLoopTri *looptri, - const MVert *mvert, - const int *face_indices, const int *sculpt_face_sets, - const int face_indices_len, - const struct Mesh *mesh) + const int *face_indices, + const int face_indices_len) { GPU_PBVH_Buffers *buffers; int i, tottri; int tot_real_edges = 0; + const MPoly *mpoly = mesh->mpoly; + const MLoop *mloop = mesh->mloop; + buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); /* smooth or flat for all */ @@ -480,7 +477,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, /* Count the number of visible triangles */ for (i = 0, tottri = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; - if (gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) { + if (gpu_pbvh_is_looptri_visible(lt, vertices, mloop, sculpt_face_sets)) { int r_edges[3]; BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); for (int j = 0; j < 3; j++) { @@ -513,7 +510,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, const MLoopTri *lt = &looptri[face_indices[i]]; /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, vertices, mloop, sculpt_face_sets)) { continue; } @@ -1246,9 +1243,7 @@ static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask, } } - /* ensure render layer is last - draw cache code seems to need this - */ + /* Ensure render layer is last, draw cache code seems to need this. */ for (int i = 0; i < count; i++) { GPUAttrRef *ref = r_cd_attrs + i; diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 82441c3c89c..4a45a3e63ed 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -280,6 +280,7 @@ class GPUCodegen { void node_serialize(std::stringstream &eval_ss, const GPUNode *node); char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link); + char *graph_serialize(eGPUNodeTag tree_tag); static char *extract_c_str(std::stringstream &stream) { @@ -500,6 +501,19 @@ char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link return eval_c_str; } +char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag) +{ + std::stringstream eval_ss; + LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { + if (node->tag & tree_tag) { + node_serialize(eval_ss, node); + } + } + char *eval_c_str = extract_c_str(eval_ss); + BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size()); + return eval_c_str; +} + void GPUCodegen::generate_uniform_buffer() { /* Extract uniform inputs. */ @@ -539,6 +553,9 @@ void GPUCodegen::generate_graphs() output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume); output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement); output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness); + if (!BLI_listbase_is_empty(&graph.outlink_compositor)) { + output.composite = graph_serialize(GPU_NODE_TAG_COMPOSITOR); + } if (!BLI_listbase_is_empty(&graph.material_functions)) { std::stringstream eval_ss; @@ -569,9 +586,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, GPUCodegenCallbackFn finalize_source_cb, void *thunk) { - /* Prune the unused nodes and extract attributes before compiling so the - * generated VBOs are ready to accept the future shader. */ gpu_node_graph_prune_unused(graph); + + /* Extract attributes before compiling so the generated VBOs are ready to accept the future + * shader. */ gpu_node_graph_finalize_uniform_attrs(graph); GPUCodegen codegen(material, graph); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4d3ea3e0c99..a4842ef0e43 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -141,7 +141,7 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat) mat->coba_builder = NULL; } -static void gpu_material_free_single(GPUMaterial *material) +void GPU_material_free_single(GPUMaterial *material) { bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0; if (!do_free) { @@ -173,7 +173,7 @@ void GPU_material_free(ListBase *gpumaterial) LISTBASE_FOREACH (LinkData *, link, gpumaterial) { GPUMaterial *material = link->data; DRW_deferred_shader_remove(material); - gpu_material_free_single(material); + GPU_material_free_single(material); } BLI_freelistN(gpumaterial); } @@ -538,6 +538,13 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, BLI_addtail(&material->graph.outlink_aovs, aov_link); } +void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link) +{ + GPUNodeGraphOutputLink *compositor_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__); + compositor_link->outlink = link; + BLI_addtail(&material->graph.outlink_compositor, compositor_link); +} + char *GPU_material_split_sub_function(GPUMaterial *material, eGPUType return_type, GPUNodeLink **link) @@ -721,7 +728,7 @@ void GPU_material_acquire(GPUMaterial *mat) void GPU_material_release(GPUMaterial *mat) { - gpu_material_free_single(mat); + GPU_material_free_single(mat); } void GPU_material_compile(GPUMaterial *mat) @@ -772,3 +779,42 @@ void GPU_materials_free(Main *bmain) // BKE_world_defaults_free_gpu(); BKE_material_defaults_free_gpu(); } + +GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, + GPUCodegenCallbackFn generate_code_function_cb, + void *thunk) +{ + /* Allocate a new material and its material graph, and initialize its reference count. */ + GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); + material->graph.used_libraries = BLI_gset_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); + material->refcount = 1; + + /* Construct the material graph by adding and linking the necessary GPU material nodes. */ + construct_function_cb(thunk, material); + + /* Create and initialize the texture storing color bands used by Ramp and Curve nodes. */ + gpu_material_ramp_texture_build(material); + + /* Lookup an existing pass in the cache or generate a new one. */ + material->pass = GPU_generate_pass(material, &material->graph, generate_code_function_cb, thunk); + + /* The pass already exists in the pass cache but its shader already failed to compile. */ + if (material->pass == NULL) { + material->status = GPU_MAT_FAILED; + gpu_node_graph_free(&material->graph); + return material; + } + + /* The pass already exists in the pass cache and its shader is already compiled. */ + GPUShader *shader = GPU_pass_shader_get(material->pass); + if (shader != NULL) { + material->status = GPU_MAT_SUCCESS; + gpu_node_graph_free_nodes(&material->graph); + return material; + } + + /* The material was created successfully but still needs to be compiled. */ + material->status = GPU_MAT_CREATED; + return material; +} diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 684070dbdc0..377cbc53893 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -75,9 +75,26 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType if (STR_ELEM(name, "set_value", "set_rgb", "set_rgba") && (input->type == type)) { input = MEM_dupallocN(outnode->inputs.first); + + switch (input->source) { + case GPU_SOURCE_ATTR: + input->attr->users++; + break; + case GPU_SOURCE_UNIFORM_ATTR: + input->uniform_attr->users++; + break; + case GPU_SOURCE_TEX: + case GPU_SOURCE_TEX_TILED_MAPPING: + input->texture->users++; + break; + default: + break; + } + if (input->link) { input->link->users++; } + BLI_addtail(&node->inputs, input); return; } @@ -179,35 +196,21 @@ static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat, BLI_assert(socket != NULL); BLI_assert(socket->in_out == in_out); - if ((socket->flag & SOCK_HIDE_VALUE) == 0) { - GPUNodeLink *link; - switch (socket->type) { - case SOCK_FLOAT: { - bNodeSocketValueFloat *socket_data = socket->default_value; - link = GPU_uniform(&socket_data->value); - break; - } - case SOCK_VECTOR: { - bNodeSocketValueVector *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - case SOCK_RGBA: { - bNodeSocketValueRGBA *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - default: - return NULL; - break; - } + if (socket->flag & SOCK_HIDE_VALUE) { + return NULL; + } - if (in_out == SOCK_IN) { - GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); - } - return link; + if (!ELEM(socket->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA)) { + return NULL; } - return NULL; + + GPUNodeLink *link = GPU_uniform(stack->vec); + + if (in_out == SOCK_IN) { + GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); + } + + return link; } static void gpu_node_input_socket( @@ -735,14 +738,6 @@ bool GPU_stack_link(GPUMaterial *material, return valid; } -GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat, - bNode *node, - GPUNodeStack *stack, - const int index) -{ - return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); -} - /* Node Graph */ static void gpu_inputs_free(ListBase *inputs) @@ -803,6 +798,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph) { BLI_freelistN(&graph->outlink_aovs); BLI_freelistN(&graph->material_functions); + BLI_freelistN(&graph->outlink_compositor); gpu_node_graph_free_nodes(graph); BLI_freelistN(&graph->textures); @@ -855,6 +851,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) { gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION); } + LISTBASE_FOREACH (GPUNodeGraphOutputLink *, compositor_link, &graph->outlink_compositor) { + gpu_nodes_tag(compositor_link->outlink, GPU_NODE_TAG_COMPOSITOR); + } for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) { next = node->next; diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index ae472d5b7aa..08ff8bbef58 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -59,6 +59,7 @@ typedef enum { GPU_NODE_TAG_THICKNESS = (1 << 3), GPU_NODE_TAG_AOV = (1 << 4), GPU_NODE_TAG_FUNCTION = (1 << 5), + GPU_NODE_TAG_COMPOSITOR = (1 << 6), } eGPUNodeTag; ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION) @@ -158,6 +159,8 @@ typedef struct GPUNodeGraph { ListBase outlink_aovs; /* List of GPUNodeGraphFunctionLink */ ListBase material_functions; + /* List of GPUNodeGraphOutputLink */ + ListBase outlink_compositor; /* Requested attributes and textures. */ ListBase attributes; diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index fe9aacb95f9..8a630d9e3ca 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -7,6 +7,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_matrix.h" #include "BLI_string_utils.h" #include "GPU_capabilities.h" @@ -382,6 +383,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) sources.append(resources.c_str()); sources.append(layout.c_str()); sources.extend(code); + sources.extend(info.dependencies_generated); + sources.append(info.compute_source_generated.c_str()); shader->compute_shader_from_glsl(sources); } @@ -702,12 +705,25 @@ void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4] GPU_shader_uniform_vector(sh, loc, 4, 1, data); } +void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]) +{ + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector_int(sh, loc, 2, 1, data); +} + void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]) { const int loc = GPU_shader_get_uniform(sh, name); GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data); } +void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]) +{ + float matrix[4][4]; + copy_m4_m3(matrix, data); + GPU_shader_uniform_mat4(sh, name, matrix); +} + void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]) { const int loc = GPU_shader_get_uniform(sh, name); diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 8e05412d0ee..fb8efbb209a 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -298,6 +298,7 @@ struct ShaderCreateInfo { /** Manually set generated code. */ std::string vertex_source_generated = ""; std::string fragment_source_generated = ""; + std::string compute_source_generated = ""; std::string geometry_source_generated = ""; std::string typedef_source_generated = ""; /** Manually set generated dependencies. */ @@ -818,6 +819,7 @@ struct ShaderCreateInfo { TEST_EQUAL(*this, b, builtins_); TEST_EQUAL(*this, b, vertex_source_generated); TEST_EQUAL(*this, b, fragment_source_generated); + TEST_EQUAL(*this, b, compute_source_generated); TEST_EQUAL(*this, b, typedef_source_generated); TEST_VECTOR_EQUAL(*this, b, vertex_inputs_); TEST_EQUAL(*this, b, geometry_layout_); diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index d91e15243f3..aff7df9ac33 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -593,7 +593,8 @@ struct GPUSource { bool is_from_material_library() const { return (filename.startswith("gpu_shader_material_") || - filename.startswith("gpu_shader_common_")) && + filename.startswith("gpu_shader_common_") || + filename.startswith("gpu_shader_compositor_")) && filename.endswith(".glsl"); } }; diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 218d22ddf53..e52311b3bf0 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -641,6 +641,112 @@ eGPUTextureFormat GPU_texture_format(const GPUTexture *tex) return reinterpret_cast<const Texture *>(tex)->format_get(); } +const char *GPU_texture_format_description(eGPUTextureFormat texture_format) +{ + switch (texture_format) { + case GPU_RGBA8UI: + return "RGBA8UI"; + case GPU_RGBA8I: + return "RGBA8I"; + case GPU_RGBA8: + return "RGBA8"; + case GPU_RGBA32UI: + return "RGBA32UI"; + case GPU_RGBA32I: + return "RGBA32I"; + case GPU_RGBA32F: + return "RGBA32F"; + case GPU_RGBA16UI: + return "RGBA16UI"; + case GPU_RGBA16I: + return "RGBA16I"; + case GPU_RGBA16F: + return "RGBA16F"; + case GPU_RGBA16: + return "RGBA16"; + case GPU_RG8UI: + return "RG8UI"; + case GPU_RG8I: + return "RG8I"; + case GPU_RG8: + return "RG8"; + case GPU_RG32UI: + return "RG32UI"; + case GPU_RG32I: + return "RG32I"; + case GPU_RG32F: + return "RG32F"; + case GPU_RG16UI: + return "RG16UI"; + case GPU_RG16I: + return "RG16I"; + case GPU_RG16F: + return "RG16F"; + case GPU_RG16: + return "RG16"; + case GPU_R8UI: + return "R8UI"; + case GPU_R8I: + return "R8I"; + case GPU_R8: + return "R8"; + case GPU_R32UI: + return "R32UI"; + case GPU_R32I: + return "R32I"; + case GPU_R32F: + return "R32F"; + case GPU_R16UI: + return "R16UI"; + case GPU_R16I: + return "R16I"; + case GPU_R16F: + return "R16F"; + case GPU_R16: + return "R16"; + + /* Special formats texture & render-buffer. */ + case GPU_RGB10_A2: + return "RGB10A2"; + case GPU_R11F_G11F_B10F: + return "R11FG11FB10F"; + case GPU_DEPTH32F_STENCIL8: + return "DEPTH32FSTENCIL8"; + case GPU_DEPTH24_STENCIL8: + return "DEPTH24STENCIL8"; + case GPU_SRGB8_A8: + return "SRGB8A8"; + + /* Texture only format */ + case (GPU_RGB16F): + return "RGB16F"; + + /* Special formats texture only */ + case GPU_SRGB8_A8_DXT1: + return "SRGB8_A8_DXT1"; + case GPU_SRGB8_A8_DXT3: + return "SRGB8_A8_DXT3"; + case GPU_SRGB8_A8_DXT5: + return "SRGB8_A8_DXT5"; + case GPU_RGBA8_DXT1: + return "RGBA8_DXT1"; + case GPU_RGBA8_DXT3: + return "RGBA8_DXT3"; + case GPU_RGBA8_DXT5: + return "RGBA8_DXT5"; + + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: + return "DEPTH32F"; + case GPU_DEPTH_COMPONENT24: + return "DEPTH24"; + case GPU_DEPTH_COMPONENT16: + return "DEPTH16"; + } + BLI_assert_unreachable(); + return ""; +} + bool GPU_texture_depth(const GPUTexture *tex) { return (reinterpret_cast<const Texture *>(tex)->format_flag_get() & GPU_FORMAT_DEPTH) != 0; diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index e425b87afe8..8646d94e2fd 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -133,11 +133,11 @@ class GLBackend : public GPUBackend { dynamic_cast<GLStorageBuf *>(indirect_buf)->bind_as(GL_DISPATCH_INDIRECT_BUFFER); /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ - glMemoryBarrier(GL_DRAW_INDIRECT_BUFFER); + glMemoryBarrier(GL_COMMAND_BARRIER_BIT); glDispatchComputeIndirect((GLintptr)0); /* Unbind. */ - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); + glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0); } /* Render Frame Coordination */ diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index fde2a53bb0f..4ec86b98cbe 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -18,6 +18,7 @@ #include "gl_debug.hh" #include "gl_index_buffer.hh" #include "gl_primitive.hh" +#include "gl_storage_buffer.hh" #include "gl_vertex_array.hh" #include "gl_batch.hh" @@ -326,4 +327,27 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) } } +void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf) +{ + GL_CHECK_RESOURCES("Batch"); + + this->bind(0); + + dynamic_cast<GLStorageBuf *>(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER); + /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ + glMemoryBarrier(GL_COMMAND_BARRIER_BIT); + + GLenum gl_type = to_gl(prim_type); + if (elem) { + const GLIndexBuf *el = this->elem_(); + GLenum index_type = to_gl(el->index_type_); + glDrawElementsIndirect(gl_type, index_type, (GLvoid *)nullptr); + } + else { + glDrawArraysIndirect(gl_type, (GLvoid *)nullptr); + } + /* Unbind. */ + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); +} + /** \} */ diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index 1a18572c683..bb53d9b31f1 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -93,6 +93,7 @@ class GLBatch : public Batch { public: void draw(int v_first, int v_count, int i_first, int i_count) override; + void draw_indirect(GPUStorageBuf *indirect_buf) override; void bind(int i_first); /* Convenience getters. */ diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc index 8be4ac29af6..46422124112 100644 --- a/source/blender/gpu/opengl/gl_state.cc +++ b/source/blender/gpu/opengl/gl_state.cc @@ -563,14 +563,14 @@ void GLStateManager::image_bind(Texture *tex_, int unit) } images_[unit] = tex->tex_id_; formats_[unit] = to_gl_internal_format(tex->format_); - tex->is_bound_ = true; + tex->is_bound_image_ = true; dirty_image_binds_ |= 1ULL << unit; } void GLStateManager::image_unbind(Texture *tex_) { GLTexture *tex = static_cast<GLTexture *>(tex_); - if (!tex->is_bound_) { + if (!tex->is_bound_image_) { return; } @@ -581,7 +581,7 @@ void GLStateManager::image_unbind(Texture *tex_) dirty_image_binds_ |= 1ULL << i; } } - tex->is_bound_ = false; + tex->is_bound_image_ = false; } void GLStateManager::image_unbind_all() diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index cfb3184c4a5..2ce205353a3 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -40,6 +40,7 @@ GLTexture::~GLTexture() if (ctx != nullptr && is_bound_) { /* This avoid errors when the texture is still inside the bound texture array. */ ctx->state_manager->texture_unbind(this); + ctx->state_manager->image_unbind(this); } GLContext::tex_free(tex_id_); } diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index aeb9fc0e6b7..22c21d360c7 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -37,6 +37,8 @@ class GLTexture : public Texture { /** True if this texture is bound to at least one texture unit. */ /* TODO(fclem): How do we ensure thread safety here? */ bool is_bound_ = false; + /** Same as is_bound_ but for image slots. */ + bool is_bound_image_ = false; /** True if pixels in the texture have been initialized. */ bool has_pixels_ = false; diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 20c414bb1ad..28125c006eb 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -41,6 +41,7 @@ /* for bool */ #include "../blenlib/BLI_sys_types.h" +#include "../gpu/GPU_texture.h" #ifdef __cplusplus extern "C" { @@ -74,12 +75,6 @@ struct Stereo3dFormat; /** * - * \attention defined in GPU_texture.h - */ -struct GPUTexture; - -/** - * * \attention Defined in allocimbuf.c */ void IMB_init(void); @@ -933,22 +928,25 @@ const char *IMB_ffmpeg_last_error(void); * * \attention defined in util_gpu.c */ -struct GPUTexture *IMB_create_gpu_texture(const char *name, - struct ImBuf *ibuf, - bool use_high_bitdepth, - bool use_premult); +GPUTexture *IMB_create_gpu_texture(const char *name, + struct ImBuf *ibuf, + bool use_high_bitdepth, + bool use_premult); + +eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, bool high_bitdepth); + /** * The `ibuf` is only here to detect the storage type. The produced texture will have undefined * content. It will need to be populated by using #IMB_update_gpu_texture_sub(). */ -struct GPUTexture *IMB_touch_gpu_texture( +GPUTexture *IMB_touch_gpu_texture( const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth); /** * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated. * Will resize the ibuf if needed. * Z is the layer to update. Unused if the texture is 2D. */ -void IMB_update_gpu_texture_sub(struct GPUTexture *tex, +void IMB_update_gpu_texture_sub(GPUTexture *tex, struct ImBuf *ibuf, int x, int y, diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index 5feb0ceb515..727704e27e8 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -290,3 +290,13 @@ GPUTexture *IMB_create_gpu_texture(const char *name, return tex; } + +eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf, bool high_bitdepth) +{ + eGPUTextureFormat gpu_texture_format; + eGPUDataFormat gpu_data_format; + + imb_gpu_get_format(ibuf, high_bitdepth, &gpu_data_format, &gpu_texture_format); + + return gpu_texture_format; +} diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt index a6818c0bf5d..ee5c6a0a47f 100644 --- a/source/blender/io/common/CMakeLists.txt +++ b/source/blender/io/common/CMakeLists.txt @@ -19,15 +19,15 @@ set(SRC intern/dupli_parent_finder.cc intern/dupli_persistent_id.cc intern/object_identifier.cc - intern/path_util.cc intern/orientation.c + intern/path_util.cc IO_abstract_hierarchy_iterator.h IO_dupli_persistent_id.hh + IO_orientation.h IO_path_util.hh IO_path_util_types.h IO_types.h - IO_orientation.h intern/dupli_parent_finder.hh ) diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h index 215891e3e48..eb811fa2de8 100644 --- a/source/blender/io/gpencil/gpencil_io.h +++ b/source/blender/io/gpencil/gpencil_io.h @@ -35,6 +35,8 @@ typedef struct GpencilIOParams { /** Stroke sampling factor. */ float stroke_sample; int32_t resolution; + /** Filename to be used in new objects. */ + char filename[128]; } GpencilIOParams; /* GpencilIOParams->flag. */ diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_base.cc b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc index 9b00fbaa027..6d4439243fd 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_import_base.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc @@ -14,6 +14,7 @@ #include "BKE_material.h" #include "ED_gpencil.h" +#include "ED_object.h" #include "gpencil_io_import_base.hh" @@ -27,10 +28,22 @@ GpencilImporter::GpencilImporter(const GpencilIOParams *iparams) : GpencilIO(ipa Object *GpencilImporter::create_object() { - const float *cur = scene_->cursor.location; + const float *cur_loc = scene_->cursor.location; + const float rot[3] = {0.0f}; ushort local_view_bits = (params_.v3d && params_.v3d->localvd) ? params_.v3d->local_view_uuid : (ushort)0; - Object *ob_gpencil = ED_gpencil_add_object(params_.C, cur, local_view_bits); + + Object *ob_gpencil = ED_object_add_type(params_.C, + OB_GPENCIL, + (params_.filename[0] != '\0') ? params_.filename : + nullptr, + cur_loc, + rot, + false, + local_view_bits); + + /* Set object defaults. */ + ED_gpencil_add_defaults(params_.C, ob_gpencil); return ob_gpencil; } diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt index e0c48bbbf7e..3a21da5c579 100644 --- a/source/blender/io/stl/CMakeLists.txt +++ b/source/blender/io/stl/CMakeLists.txt @@ -24,16 +24,16 @@ set(INC_SYS set(SRC IO_stl.cc - importer/stl_import_mesh.cc + importer/stl_import.cc importer/stl_import_ascii_reader.cc importer/stl_import_binary_reader.cc - importer/stl_import.cc + importer/stl_import_mesh.cc IO_stl.h - importer/stl_import_mesh.hh + importer/stl_import.hh importer/stl_import_ascii_reader.hh importer/stl_import_binary_reader.hh - importer/stl_import.hh + importer/stl_import_mesh.hh ) set(LIB diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index 8feceee55ed..f59b8be147e 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -9,8 +9,11 @@ #include "BKE_node.h" #include "BKE_node_tree_update.h" +#include "BLI_fileops.h" #include "BLI_math_vector.h" +#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_vector.hh" #include "DNA_material_types.h" @@ -94,6 +97,60 @@ static void link_nodes( nodeAddLink(ntree, source, source_socket, dest, dest_socket); } +/* Returns a layer handle retrieved from the given attribute's property specs. + * Note that the returned handle may be invalid if no layer could be found. */ +static pxr::SdfLayerHandle get_layer_handle(const pxr::UsdAttribute &attribute) +{ + for (auto PropertySpec : attribute.GetPropertyStack(pxr::UsdTimeCode::EarliestTime())) { + if (PropertySpec->HasDefaultValue() || + PropertySpec->GetLayer()->GetNumTimeSamplesForPath(PropertySpec->GetPath()) > 0) { + return PropertySpec->GetLayer(); + } + } + + return pxr::SdfLayerHandle(); +} + +static bool is_udim_path(const std::string &path) +{ + return path.find("<UDIM>") != std::string::npos; +} + +/* For the given UDIM path (assumed to contain the UDIM token), returns an array + * containing valid tile indices. */ +static blender::Vector<int> get_udim_tiles(const std::string &file_path) +{ + char base_udim_path[FILE_MAX]; + BLI_strncpy(base_udim_path, file_path.c_str(), sizeof(base_udim_path)); + + blender::Vector<int> udim_tiles; + + /* Extract the tile numbers from all files on disk. */ + ListBase tiles = {nullptr, nullptr}; + int tile_start, tile_range; + bool result = BKE_image_get_tile_info(base_udim_path, &tiles, &tile_start, &tile_range); + if (result) { + LISTBASE_FOREACH (LinkData *, tile, &tiles) { + int tile_number = POINTER_AS_INT(tile->data); + udim_tiles.append(tile_number); + } + } + + BLI_freelistN(&tiles); + + return udim_tiles; +} + +/* Add tiles with the given indices to the given image. */ +static void add_udim_tiles(Image *image, const blender::Vector<int> &indices) +{ + image->source = IMA_SRC_TILED; + + for (int tile_number : indices) { + BKE_image_add_tile(image, tile_number, nullptr); + } +} + /* Returns true if the given shader may have opacity < 1.0, based * on heuristics. */ static bool needs_blend(const pxr::UsdShadeShader &usd_shader) @@ -601,11 +658,31 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader, const pxr::SdfAssetPath &asset_path = file_val.Get<pxr::SdfAssetPath>(); std::string file_path = asset_path.GetResolvedPath(); if (file_path.empty()) { + /* No resolved path, so use the asset path (usually + * necessary for UDIM paths). */ + file_path = asset_path.GetAssetPath(); + + /* Texture paths are frequently relative to the USD, so get + * the absolute path. */ + if (pxr::SdfLayerHandle layer_handle = get_layer_handle(file_input.GetAttr())) { + file_path = layer_handle->ComputeAbsolutePath(file_path); + } + } + + if (file_path.empty()) { std::cerr << "WARNING: Couldn't resolve image asset '" << asset_path << "' for Texture Image node." << std::endl; return; } + /* If this is a UDIM texture, this will store the + * UDIM tile indices. */ + blender::Vector<int> udim_tiles; + + if (is_udim_path(file_path)) { + udim_tiles = get_udim_tiles(file_path); + } + const char *im_file = file_path.c_str(); Image *image = BKE_image_load_exists(bmain_, im_file); if (!image) { @@ -614,6 +691,10 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader, return; } + if (udim_tiles.size() > 0) { + add_udim_tiles(image, udim_tiles); + } + tex_image->id = &image->id; /* Set texture color space. diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 45657525527..f65657b240c 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -64,7 +64,22 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> * static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim) { - return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial(); + pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim); + + /* Compute generically bound ('allPurpose') materials. */ + pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial(); + + /* If no generic material could be resolved, also check for 'preview' and + * 'full' purpose materials as fallbacks. */ + if (!mtl) { + mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview); + } + + if (!mtl) { + mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full); + } + + return mtl; } /* Returns an existing Blender material that corresponds to the USD diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc index 9a457167fca..7e282b164b0 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc @@ -41,12 +41,14 @@ void fixup_line_continuations(char *p, char *end) while (true) { /* Find next backslash, if any. */ char *backslash = std::find(p, end, '\\'); - if (backslash == end) + if (backslash == end) { break; + } /* Skip over possible whitespace right after it. */ p = backslash + 1; - while (p < end && is_whitespace(*p) && *p != '\n') + while (p < end && is_whitespace(*p) && *p != '\n') { ++p; + } /* If then we have a newline, turn both backslash * and the newline into regular spaces. */ if (p < end && *p == '\n') { diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index a77b7034241..b3a07f7ff37 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -37,7 +37,7 @@ typedef struct DrawData { /* Only nested data, NOT the engine data itself. */ DrawDataFreeCb free; /* Accumulated recalc flags, which corresponds to ID->recalc flags. */ - int recalc; + unsigned int recalc; } DrawData; typedef struct DrawDataList { @@ -256,6 +256,7 @@ typedef struct IDOverrideLibraryProperty { /** * List of overriding operations (IDOverrideLibraryPropertyOperation) applied to this property. + * Recreated as part of the diffing, so do not store any of these elsewhere. */ ListBase operations; @@ -387,7 +388,7 @@ typedef struct ID { int tag; int us; int icon_id; - int recalc; + unsigned int recalc; /** * Used by undo code. recalc_after_undo_push contains the changes between the * last undo push and the current state. This is accumulated as IDs are tagged @@ -397,8 +398,8 @@ typedef struct ID { * recalc_after_undo_push at the time of the undo push. This means it can be * used to find the changes between undo states. */ - int recalc_up_to_undo_push; - int recalc_after_undo_push; + unsigned int recalc_up_to_undo_push; + unsigned int recalc_after_undo_push; /** * A session-wide unique identifier for a given ID, that remain the same across potential @@ -870,6 +871,17 @@ typedef enum IDRecalcFlag { /* The node tree has changed in a way that affects its output nodes. */ ID_RECALC_NTREE_OUTPUT = (1 << 25), + /* Provisioned flags. + * + * Not for actual use. The idea of them is to have all bits of the `IDRecalcFlag` defined to a + * known value, silencing sanitizer warnings when checking bits of the ID_RECALC_ALL. */ + ID_RECALC_PROVISION_26 = (1 << 26), + ID_RECALC_PROVISION_27 = (1 << 27), + ID_RECALC_PROVISION_28 = (1 << 28), + ID_RECALC_PROVISION_29 = (1 << 29), + ID_RECALC_PROVISION_30 = (1 << 30), + ID_RECALC_PROVISION_31 = (1u << 31), + /*************************************************************************** * Pseudonyms, to have more semantic meaning in the actual code without * using too much low-level and implementation specific tags. */ @@ -888,7 +900,8 @@ typedef enum IDRecalcFlag { * Do NOT use those for tagging. */ /* Identifies that SOMETHING has been changed in this ID. */ - ID_RECALC_ALL = ~(0), + ID_RECALC_ALL = (0xffffffff), + /* Identifies that something in particle system did change. */ ID_RECALC_PSYS_ALL = (ID_RECALC_PSYS_REDO | ID_RECALC_PSYS_RESET | ID_RECALC_PSYS_CHILD | ID_RECALC_PSYS_PHYS), diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index d49d0906aa7..29795519719 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -96,7 +96,7 @@ typedef enum eAssetLibraryType { } eAssetLibraryType; /** - * Information to identify a asset library. May be either one of the predefined types (current + * Information to identify an asset library. May be either one of the predefined types (current * 'Main', builtin library, project library), or a custom type as defined in the Preferences. * * If the type is set to #ASSET_LIBRARY_CUSTOM, `custom_library_index` must be set to identify the diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 6e4e515a0fe..f35c77f663b 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -92,8 +92,14 @@ typedef struct ImageTile { struct ImageTile_Runtime runtime; - char _pad[4]; int tile_number; + + /* for generated images */ + int gen_x, gen_y; + char gen_type, gen_flag; + short gen_depth; + float gen_color[4]; + char label[64]; } ImageTile; @@ -167,10 +173,10 @@ typedef struct Image { int lastused; /* for generated images */ - int gen_x, gen_y; - char gen_type, gen_flag; - short gen_depth; - float gen_color[4]; + int gen_x DNA_DEPRECATED, gen_y DNA_DEPRECATED; + char gen_type DNA_DEPRECATED, gen_flag DNA_DEPRECATED; + short gen_depth DNA_DEPRECATED; + float gen_color[4] DNA_DEPRECATED; /* display aspect - for UV editing images resized for faster openGL display */ float aspx, aspy; @@ -262,7 +268,8 @@ enum { /** #Image.gen_flag */ enum { - IMA_GEN_FLOAT = 1, + IMA_GEN_FLOAT = (1 << 0), + IMA_GEN_TILE = (1 << 1), }; /** #Image.alpha_mode */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 0af50b2bd4f..345fa141514 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -37,7 +37,7 @@ typedef enum eViewLayerEEVEEPassType { EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16), EEVEE_RENDER_PASS_VECTOR = (1 << 17), } eViewLayerEEVEEPassType; -#define EEVEE_RENDER_PASS_MAX_BIT 17 +#define EEVEE_RENDER_PASS_MAX_BIT 18 /* #ViewLayerAOV.type */ typedef enum eViewLayerAOVType { diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 2a4234bde6a..4090c45a753 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -55,7 +55,6 @@ enum { /* ME_HIDE = (1 << 4), */ ME_EDGERENDER = (1 << 5), ME_LOOSEEDGE = (1 << 7), - ME_EDGE_TMP_TAG = (1 << 8), ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */ }; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index b4fa7088d38..4b8f8ca7b4b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -650,7 +650,7 @@ static ID *rna_ID_evaluated_get(ID *id, struct Depsgraph *depsgraph) static ID *rna_ID_copy(ID *id, Main *bmain) { - ID *newid = BKE_id_copy(bmain, id); + ID *newid = BKE_id_copy_for_use_in_bmain(bmain, id); if (newid != NULL) { id_us_min(newid); @@ -2045,7 +2045,10 @@ static void rna_def_ID(BlenderRNA *brna) func = RNA_def_function(srna, "copy", "rna_ID_copy"); RNA_def_function_ui_description( - func, "Create a copy of this data-block (not supported for all data-blocks)"); + func, + "Create a copy of this data-block (not supported for all data-blocks). " + "The result is added to the Blend-File Data (Main database), with all references to other " + "data-blocks ensured to be from within the same Blend-File Data"); RNA_def_function_flag(func, FUNC_USE_MAIN); parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 7f134c5055f..b7ab7689dd7 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -52,6 +52,7 @@ static const EnumPropertyItem image_source_items[] = { #ifdef RNA_RUNTIME # include "BLI_math_base.h" +# include "BLI_math_vector.h" # include "BKE_global.h" @@ -85,6 +86,10 @@ static void rna_Image_source_set(PointerRNA *ptr, int value) ima->source = value; BLI_assert(BKE_id_is_in_global_main(&ima->id)); BKE_image_signal(G_MAIN, ima, NULL, IMA_SIGNAL_SRC_CHANGE); + if (ima->source == IMA_SRC_TILED) { + BKE_image_signal(G_MAIN, ima, NULL, IMA_SIGNAL_RELOAD); + } + DEG_id_tag_update(&ima->id, 0); DEG_id_tag_update(&ima->id, ID_RECALC_EDITORS); DEG_relations_tag_update(G_MAIN); @@ -100,6 +105,83 @@ static void rna_Image_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRN DEG_id_tag_update(&ima->id, ID_RECALC_EDITORS); } +static int rna_Image_generated_type_get(PointerRNA *ptr) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + return base_tile->gen_type; +} + +static void rna_Image_generated_type_set(PointerRNA *ptr, int value) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_type = value; +} + +static int rna_Image_generated_width_get(PointerRNA *ptr) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + return base_tile->gen_x; +} + +static void rna_Image_generated_width_set(PointerRNA *ptr, int value) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_x = CLAMPIS(value, 1, 65536); +} + +static int rna_Image_generated_height_get(PointerRNA *ptr) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + return base_tile->gen_y; +} + +static void rna_Image_generated_height_set(PointerRNA *ptr, int value) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_y = CLAMPIS(value, 1, 65536); +} + +static bool rna_Image_generated_float_get(PointerRNA *ptr) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + return (base_tile->gen_flag & IMA_GEN_FLOAT) != 0; +} + +static void rna_Image_generated_float_set(PointerRNA *ptr, bool value) +{ + Image *ima = (Image *)ptr->data; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (value) { + base_tile->gen_flag |= IMA_GEN_FLOAT; + } + else { + base_tile->gen_flag &= ~IMA_GEN_FLOAT; + } +} + +void rna_Image_generated_color_get(PointerRNA *ptr, float values[4]) +{ + Image *ima = (Image *)(ptr->data); + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + copy_v4_v4(values, base_tile->gen_color); +} + +void rna_Image_generated_color_set(PointerRNA *ptr, const float values[4]) +{ + Image *ima = (Image *)(ptr->data); + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + for (unsigned int i = 0; i < 4; i++) { + base_tile->gen_color[i] = CLAMPIS(values[i], 0.0f, FLT_MAX); + } +} + static void rna_Image_generated_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Image *ima = (Image *)ptr->owner_id; @@ -335,6 +417,20 @@ static void rna_UDIMTile_tile_number_set(PointerRNA *ptr, int value) } } +static void rna_UDIMTile_generated_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *ptr) +{ + Image *ima = (Image *)ptr->owner_id; + ImageTile *tile = (ImageTile *)ptr->data; + + /* If the tile is still marked as generated, then update the tile as requested. */ + if ((tile->gen_flag & IMA_GEN_TILE) != 0) { + BKE_image_fill_tile(ima, tile); + BKE_image_partial_update_mark_full_update(ima); + } +} + static int rna_Image_active_tile_index_get(PointerRNA *ptr) { Image *image = (Image *)ptr->data; @@ -896,6 +992,43 @@ static void rna_def_udim_tile(BlenderRNA *brna) RNA_def_property_int_funcs(prop, "rna_UDIMTile_channels_get", NULL, NULL); RNA_def_property_ui_text(prop, "Channels", "Number of channels in the tile pixels buffer"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* Generated tile information. */ + prop = RNA_def_property(srna, "generated_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "gen_type"); + RNA_def_property_enum_items(prop, rna_enum_image_generated_type_items); + RNA_def_property_ui_text(prop, "Generated Type", "Generated image type"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_UDIMTile_generated_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "generated_width", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "gen_x"); + RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_range(prop, 1, 65536); + RNA_def_property_ui_text(prop, "Generated Width", "Generated image width"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_UDIMTile_generated_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "generated_height", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "gen_y"); + RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_range(prop, 1, 65536); + RNA_def_property_ui_text(prop, "Generated Height", "Generated image height"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_UDIMTile_generated_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "use_generated_float", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gen_flag", IMA_GEN_FLOAT); + RNA_def_property_ui_text(prop, "Float Buffer", "Generate floating-point buffer"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_UDIMTile_generated_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "generated_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gen_color"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Color", "Fill color for the generated image"); + RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_UDIMTile_generated_update"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop) @@ -1079,6 +1212,8 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "gen_type"); RNA_def_property_enum_items(prop, rna_enum_image_generated_type_items); RNA_def_property_ui_text(prop, "Generated Type", "Generated image type"); + RNA_def_property_enum_funcs( + prop, "rna_Image_generated_type_get", "rna_Image_generated_type_set", NULL); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -1087,6 +1222,8 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, 65536); RNA_def_property_ui_text(prop, "Generated Width", "Generated image width"); + RNA_def_property_int_funcs( + prop, "rna_Image_generated_width_get", "rna_Image_generated_width_set", NULL); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -1095,12 +1232,16 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, 65536); RNA_def_property_ui_text(prop, "Generated Height", "Generated image height"); + RNA_def_property_int_funcs( + prop, "rna_Image_generated_height_get", "rna_Image_generated_height_set", NULL); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); prop = RNA_def_property(srna, "use_generated_float", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gen_flag", IMA_GEN_FLOAT); RNA_def_property_ui_text(prop, "Float Buffer", "Generate floating-point buffer"); + RNA_def_property_boolean_funcs( + prop, "rna_Image_generated_float_get", "rna_Image_generated_float_set"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -1108,6 +1249,8 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "gen_color"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Color", "Fill color for the generated image"); + RNA_def_property_float_funcs( + prop, "rna_Image_generated_color_get", "rna_Image_generated_color_set", NULL); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 65468977ccb..9aef19c8230 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1608,9 +1608,7 @@ static void rna_Mesh_vertex_color_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer) { - if (ED_mesh_color_remove_named(me, layer->name) == false) { - BKE_reportf(reports, RPT_ERROR, "Vertex color '%s' not found", layer->name); - } + BKE_id_attribute_remove(&me->id, layer->name, reports); } static PointerRNA rna_Mesh_sculpt_vertex_color_new(struct Mesh *me, @@ -1621,7 +1619,7 @@ static PointerRNA rna_Mesh_sculpt_vertex_color_new(struct Mesh *me, PointerRNA ptr; CustomData *vdata; CustomDataLayer *cdl = NULL; - int index = ED_mesh_sculpt_color_add(me, name, false, do_init, reports); + int index = ED_mesh_sculpt_color_add(me, name, do_init, reports); if (index != -1) { vdata = rna_mesh_vdata_helper(me); @@ -1636,9 +1634,7 @@ static void rna_Mesh_sculpt_vertex_color_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer) { - if (ED_mesh_sculpt_color_remove_named(me, layer->name) == false) { - BKE_reportf(reports, RPT_ERROR, "Sculpt vertex color '%s' not found", layer->name); - } + BKE_id_attribute_remove(&me->id, layer->name, reports); } # define DEFINE_CUSTOMDATA_PROPERTY_API( \ diff --git a/source/blender/makesrna/intern/rna_path.cc b/source/blender/makesrna/intern/rna_path.cc index c1613e3927e..5d570657b53 100644 --- a/source/blender/makesrna/intern/rna_path.cc +++ b/source/blender/makesrna/intern/rna_path.cc @@ -380,9 +380,7 @@ static bool rna_path_parse(const PointerRNA *ptr, } const bool use_id_prop = (*path == '['); - /* custom property lookup ? - * C.object["someprop"] - */ + /* Custom property lookup: e.g. `C.object["someprop"]`. */ if (!curptr.data) { return false; @@ -706,7 +704,7 @@ const char *RNA_path_array_index_token_find(const char *rna_path, const Property /* Valid 'array part' of a rna path can only have '[', ']' and digit characters. * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */ - size_t rna_path_len = (size_t)strlen(rna_path); + int64_t rna_path_len = (int64_t)strlen(rna_path); if (rna_path[rna_path_len] != ']') { return NULL; } @@ -809,7 +807,7 @@ static char *rna_idp_path(PointerRNA *ptr, link.name = NULL; link.index = -1; - for (i = 0, iter = reinterpret_cast<IDProperty *>(haystack->data.group.first); iter; + for (i = 0, iter = static_cast<IDProperty *>(haystack->data.group.first); iter; iter = iter->next, i++) { if (needle == iter) { /* found! */ link.name = iter->name; @@ -911,7 +909,7 @@ static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr) */ RNA_id_pointer_create(ptr->owner_id, &id_ptr); - return RNA_path_from_struct_to_idproperty(&id_ptr, reinterpret_cast<IDProperty *>(ptr->data)); + return RNA_path_from_struct_to_idproperty(&id_ptr, static_cast<IDProperty *>(ptr->data)); } ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index dabb89bcd5e..adb959944b5 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -473,7 +473,7 @@ static int rna_UIList_list_id_length(PointerRNA *ptr) } static void uilist_draw_item(uiList *ui_list, - bContext *C, + const bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr, @@ -507,7 +507,7 @@ static void uilist_draw_item(uiList *ui_list, RNA_parameter_list_free(&list); } -static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout) +static void uilist_draw_filter(uiList *ui_list, const bContext *C, uiLayout *layout) { extern FunctionRNA rna_UIList_draw_filter_func; @@ -527,7 +527,7 @@ static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout) } static void uilist_filter_items(uiList *ui_list, - bContext *C, + const bContext *C, PointerRNA *dataptr, const char *propname) { diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 15ad361a262..3fce556ce77 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -125,7 +125,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_object_relation(ctx->node, amd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier"); } - DEG_add_modifier_to_transform_relation(ctx->node, "Armature Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Armature Modifier"); } static void deformVerts(ModifierData *md, diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 569b0fd0fda..b29b34436ca 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -93,7 +93,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_dependency) { - DEG_add_modifier_to_transform_relation(ctx->node, "Array Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Array Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index aa64c1f83bc..685338cf351 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -117,7 +117,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_collection_geometry_relation(ctx->node, col, "Boolean Modifier"); } /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "Boolean Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Boolean Modifier"); } static Mesh *get_quick_mesh( diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 9aaf7fead36..874dd20691f 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -87,7 +87,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte CastModifierData *cmd = (CastModifierData *)md; if (cmd->object != NULL) { DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Cast Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Cast Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index cc0bd87d614..4fe65bf28ac 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -144,7 +144,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_forcefield_relations( ctx->node, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); } - DEG_add_modifier_to_transform_relation(ctx->node, "Cloth Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Cloth Modifier"); } static void requiredDataMask(Object *UNUSED(ob), diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 74cb4ac700a..868e164e223 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -236,7 +236,7 @@ static void deformVerts(ModifierData *md, static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx) { - DEG_add_modifier_to_transform_relation(ctx->node, "Collision Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Collision Modifier"); } static void panel_draw(const bContext *UNUSED(C), Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 48a59f4d949..bd622fc1373 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -97,7 +97,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_special_eval_flag(ctx->node, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH); } - DEG_add_modifier_to_transform_relation(ctx->node, "Curve Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Curve Modifier"); } static void deformVerts(ModifierData *md, diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index e9f1cf47e38..7cd6b829d37 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -129,7 +129,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte if (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) { DEG_add_object_relation( ctx->node, dtmd->ob_source, DEG_OB_COMP_TRANSFORM, "DataTransfer Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "DataTransfer Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "DataTransfer Modifier"); } } } diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 5289fc42e21..cf1bb64a41d 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -142,7 +142,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Displace Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 3c4e6b0d90f..b9942ff8a4d 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -122,7 +122,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_object_relation(ctx->node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); } /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "Hook Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Hook Modifier"); } struct HookData_cb { diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 0e1994eed36..2edcbd8e59a 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -87,7 +87,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier"); DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier"); } - DEG_add_modifier_to_transform_relation(ctx->node, "Lattice Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Lattice Modifier"); } static void deformVerts(ModifierData *md, diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index fac3ea36537..e48a949baf4 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -86,7 +86,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte /* TODO(sergey): Is it a proper relation here? */ DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier"); arm->flag |= ARM_HAS_VIZ_DEPS; - DEG_add_modifier_to_transform_relation(ctx->node, "Mask Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Mask Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index 9ac410eb3de..0471beadcc1 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -60,7 +60,7 @@ static void initData(ModifierData *md) static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md); - DEG_add_modifier_to_transform_relation(ctx->node, "Mesh to Volume Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Mesh to Volume Modifier"); if (mvmd->object) { DEG_add_object_relation( ctx->node, mvmd->object, DEG_OB_COMP_GEOMETRY, "Mesh to Volume Modifier"); diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 334f5d75279..3b7e62f99e1 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -160,7 +160,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier"); } /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "Mesh Deform Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Mesh Deform Modifier"); } static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3]) diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 5f095a72dca..f1a36c04453 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -62,7 +62,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte MirrorModifierData *mmd = (MirrorModifierData *)md; if (mmd->mirror_ob != NULL) { DEG_add_object_relation(ctx->node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Mirror Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Mirror Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 223e4b757b7..9c95561904a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -40,7 +40,7 @@ #include "BKE_geometry_fields.hh" #include "BKE_geometry_set_instances.hh" #include "BKE_global.h" -#include "BKE_idprop.h" +#include "BKE_idprop.hh" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -307,7 +307,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (needs_own_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Nodes Modifier"); } } @@ -416,15 +416,16 @@ static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int soc return field_interface.inputs[socket_index] != InputSocketFieldType::None; } -static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) +static std::unique_ptr<IDProperty, blender::bke::idprop::IDPropertyDeleter> +id_property_create_from_socket(const bNodeSocket &socket) { + using namespace blender; switch (socket.type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.f = value->value; - IDProperty *property = IDP_New(IDP_FLOAT, &idprop, socket.identifier); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = (double)value->min; ui_data->max = ui_data->soft_max = (double)value->max; @@ -432,11 +433,10 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_INT: { - bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.i = value->value; - IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier); - IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property); + const bNodeSocketValueInt *value = static_cast<const bNodeSocketValueInt *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = value->min; ui_data->max = ui_data->soft_max = value->max; @@ -444,13 +444,11 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_VECTOR: { - bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.array.len = 3; - idprop.array.type = IDP_FLOAT; - IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier); - copy_v3_v3((float *)IDP_Array(property), value->value); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>( + socket.default_value); + auto property = bke::idprop::create( + socket.identifier, Span<float>{value->value[0], value->value[1], value->value[2]}); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = (double)value->min; ui_data->max = ui_data->soft_max = (double)value->max; @@ -462,13 +460,12 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_RGBA: { - bNodeSocketValueRGBA *value = (bNodeSocketValueRGBA *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.array.len = 4; - idprop.array.type = IDP_FLOAT; - IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier); - copy_v4_v4((float *)IDP_Array(property), value->value); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>( + socket.default_value); + auto property = bke::idprop::create( + socket.identifier, + Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]}); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = PROP_COLOR; ui_data->default_array = (double *)MEM_mallocN(sizeof(double[4]), __func__); ui_data->default_array_len = 4; @@ -482,53 +479,48 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.i = value->value != 0; - IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier); - IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property); + const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, int(value->value)); + IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get()); ui_data->min = ui_data->soft_min = 0; ui_data->max = ui_data->soft_max = 1; ui_data->default_value = value->value != 0; return property; } case SOCK_STRING: { - bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value; - IDProperty *property = IDP_NewString( - value->value, socket.identifier, BLI_strnlen(value->value, sizeof(value->value)) + 1); - IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure(property); + const bNodeSocketValueString *value = static_cast<const bNodeSocketValueString *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure( + property.get()); ui_data->default_value = BLI_strdup(value->value); return property; } case SOCK_OBJECT: { - bNodeSocketValueObject *value = (bNodeSocketValueObject *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueObject *value = static_cast<const bNodeSocketValueObject *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_COLLECTION: { - bNodeSocketValueCollection *value = (bNodeSocketValueCollection *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueCollection *value = static_cast<const bNodeSocketValueCollection *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_TEXTURE: { - bNodeSocketValueTexture *value = (bNodeSocketValueTexture *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueTexture *value = static_cast<const bNodeSocketValueTexture *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_IMAGE: { - bNodeSocketValueImage *value = (bNodeSocketValueImage *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueImage *value = static_cast<const bNodeSocketValueImage *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_MATERIAL: { - bNodeSocketValueMaterial *value = (bNodeSocketValueMaterial *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueMaterial *value = static_cast<const bNodeSocketValueMaterial *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } } return nullptr; @@ -658,7 +650,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) int socket_index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) { - IDProperty *new_prop = id_property_create_from_socket(*socket); + IDProperty *new_prop = id_property_create_from_socket(*socket).release(); if (new_prop == nullptr) { /* Out of the set of supported input sockets, only * geometry sockets aren't added to the modifier. */ diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index e43d2b4ad85..5cf4e21ea68 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -1863,6 +1863,7 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier) void NodeParamsProvider::set_input_unused(StringRef identifier) { + BLI_assert(node_supports_laziness(this->dnode)); const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 09bc9546325..94b48f65a66 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -670,7 +670,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte NormalEditModifierData *enmd = (NormalEditModifierData *)md; if (enmd->target) { DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "NormalEdit Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "NormalEdit Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 9588b9acd3b..109795df796 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -1148,7 +1148,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte ScrewModifierData *ltmd = (ScrewModifierData *)md; if (ltmd->ob_axis != NULL) { DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "Screw Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Screw Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index be12dc6639b..1c4ef5698b4 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -186,7 +186,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_special_eval_flag(ctx->node, &smd->auxTarget->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); } } - DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Shrinkwrap Modifier"); } static bool dependsOnNormals(ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 9f1d0cd36c4..168575b6330 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -438,7 +438,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte if (smd->origin != NULL) { DEG_add_object_relation( ctx->node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "SimpleDeform Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "SimpleDeform Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index a49f2609641..ecff6d80893 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -66,7 +66,7 @@ static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgr ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field"); } /* We need own transformation as well. */ - DEG_add_modifier_to_transform_relation(ctx->node, "SoftBody Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "SoftBody Modifier"); } static void panel_draw(const bContext *UNUSED(C), Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 80af23054e4..4b744cd8350 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -53,7 +53,13 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) * \param poly_nors: Precalculated face normals. * \param r_vert_nors: Return vert normals. */ -static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float (*r_vert_nors)[3]) +static void mesh_calc_hq_normal(Mesh *mesh, + const float (*poly_nors)[3], + float (*r_vert_nors)[3], +#ifdef USE_NONMANIFOLD_WORKAROUND + BLI_bitmap *edge_tmp_tag +#endif +) { int i, verts_num, edges_num, polys_num; MPoly *mpoly, *mp; @@ -103,7 +109,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float ( /* 3+ faces using an edge, we can't handle this usefully */ edge_ref->p1 = edge_ref->p2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND - medge[ml->e].flag |= ME_EDGE_TMP_TAG; + BLI_BITMAP_ENABLE(edge_tmp_tag, ml->e); #endif } /* --- done --- */ @@ -319,9 +325,20 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex BLI_assert(newEdges == 0); } +#ifdef USE_NONMANIFOLD_WORKAROUND + BLI_bitmap *edge_tmp_tag = BLI_BITMAP_NEW(mesh->totedge, __func__); +#endif + if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = MEM_calloc_arrayN(verts_num, sizeof(float[3]), "mod_solid_vno_hq"); - mesh_calc_hq_normal(mesh, poly_nors, vert_nors); + mesh_calc_hq_normal(mesh, + poly_nors, + vert_nors +#ifdef USE_NONMANIFOLD_WORKAROUND + , + edge_tmp_tag +#endif + ); } result = BKE_mesh_new_nomain_from_template(mesh, @@ -740,8 +757,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex #ifdef USE_NONMANIFOLD_WORKAROUND /* skip 3+ face user edges */ if ((check_non_manifold == false) || - LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && - ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { + LIKELY(!BLI_BITMAP_TEST(edge_tmp_tag, ml[i_curr].e) && + !BLI_BITMAP_TEST(edge_tmp_tag, ml[i_next].e))) { vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; } @@ -949,6 +966,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex MEM_freeN(vert_angles); } +#ifdef USE_NONMANIFOLD_WORKAROUND + MEM_SAFE_FREE(edge_tmp_tag); +#endif + if (vert_nors) { MEM_freeN(vert_nors); } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 0474d3e47e6..a318a82fe64 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -80,7 +80,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } if (do_add_own_transform) { - DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "UV Project Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index c33b25c38e3..4178f1dd33e 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -242,7 +242,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte MOD_depsgraph_update_object_bone_relation( ctx->node, umd->object_dst, umd->bone_dst, "UVWarp Modifier"); - DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "UVWarp Modifier"); } static void panel_draw(const bContext *UNUSED(C), Panel *panel) diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 3292f73137a..215436e4a8d 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -62,7 +62,7 @@ static void initData(ModifierData *md) static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { VolumeToMeshModifierData *vmmd = reinterpret_cast<VolumeToMeshModifierData *>(md); - DEG_add_modifier_to_transform_relation(ctx->node, "Volume to Mesh Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Volume to Mesh Modifier"); if (vmmd->object) { DEG_add_object_relation( ctx->node, vmmd->object, DEG_OB_COMP_GEOMETRY, "Volume to Mesh Modifier"); diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index afdc230a877..5bef19da53a 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -171,7 +171,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "Warp Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Warp Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index b92e3a0fa9d..136ff6b6d15 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -98,7 +98,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "Wave Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index f6e0cd9303d..7ffaa120ba2 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -139,7 +139,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "WeightVGEdit Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 49088d42a5e..701e30fbf57 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -187,7 +187,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "WeightVGMix Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index b68d36366fd..70838bc5c4f 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -401,7 +401,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } if (need_transform_relation) { - DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier"); + DEG_add_depends_on_transform_relation(ctx->node, "WeightVGProximity Modifier"); } } diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 586d3e36177..786ce88152e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -404,7 +404,7 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES",Tra DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "Convert all faces in a mesh to triangular faces") DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "Shorten curves by removing portions at the start or end") DefNode(GeometryNode, GEO_NODE_UV_PACK_ISLANDS, 0, "UV_PACK_ISLANDS", UVPackIslands, "Pack UV Islands", "Scale islands of a UV map and move them so they fill the UV space as much as possible") -DefNode(GeometryNode, GEO_NODE_UV_UNWRAP, def_geo_uv_unwrap, "UV_UNWRAP", UVUnwrap, "UV Unwrap", "Generate a UV map islands based on seam edges") +DefNode(GeometryNode, GEO_NODE_UV_UNWRAP, def_geo_uv_unwrap, "UV_UNWRAP", UVUnwrap, "UV Unwrap", "Generate a UV map based on seam edges") DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "Display the input data in the Spreadsheet Editor") DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "Generate a dense volume with a field that controls the density at each grid voxel based on its position") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "Generate a mesh on the \"surface\" of a volume") diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index 32b5d98a556..6efe6f231f5 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -183,6 +183,7 @@ void register_node_tree_type_cmp() tt->type = NTREE_COMPOSIT; strcpy(tt->idname, "CompositorNodeTree"); + strcpy(tt->group_idname, "CompositorNodeGroup"); strcpy(tt->ui_name, N_("Compositor")); tt->ui_icon = ICON_NODE_COMPOSITING; strcpy(tt->ui_description, N_("Compositing nodes")); diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index ddd8c8949b1..31c00cc6b82 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -76,8 +76,8 @@ set(SRC nodes/node_geo_input_index.cc nodes/node_geo_input_instance_rotation.cc nodes/node_geo_input_instance_scale.cc - nodes/node_geo_input_material_index.cc nodes/node_geo_input_material.cc + nodes/node_geo_input_material_index.cc nodes/node_geo_input_mesh_edge_angle.cc nodes/node_geo_input_mesh_edge_neighbors.cc nodes/node_geo_input_mesh_edge_vertices.cc @@ -118,9 +118,9 @@ set(SRC nodes/node_geo_mesh_to_points.cc nodes/node_geo_mesh_to_volume.cc nodes/node_geo_object_info.cc + nodes/node_geo_points.cc nodes/node_geo_points_to_vertices.cc nodes/node_geo_points_to_volume.cc - nodes/node_geo_points.cc nodes/node_geo_proximity.cc nodes/node_geo_raycast.cc nodes/node_geo_realize_instances.cc @@ -134,8 +134,8 @@ set(SRC nodes/node_geo_set_curve_radius.cc nodes/node_geo_set_curve_tilt.cc nodes/node_geo_set_id.cc - nodes/node_geo_set_material_index.cc nodes/node_geo_set_material.cc + nodes/node_geo_set_material_index.cc nodes/node_geo_set_point_radius.cc nodes/node_geo_set_position.cc nodes/node_geo_set_shade_smooth.cc diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 38e914b9a9f..e3998322741 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -109,6 +109,7 @@ void register_node_tree_type_geo() MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type")); tt->type = NTREE_GEOMETRY; strcpy(tt->idname, "GeometryNodeTree"); + strcpy(tt->group_idname, "GeometryNodeGroup"); strcpy(tt->ui_name, N_("Geometry Node Editor")); tt->ui_icon = ICON_GEOMETRY_NODES; strcpy(tt->ui_description, N_("Geometry nodes")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index cfb9cbf7e24..cf29c752257 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -220,11 +220,11 @@ BLI_NOINLINE static void update_elimination_mask_based_on_density_factors( const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]); const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]); - const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y + + const float probability = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y + v2_density_factor * bary_coord.z; const float hash = noise::hash_float_to_float(bary_coord); - if (hash > probablity) { + if (hash > probability) { elimination_mask[i] = true; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index acf85e74353..024dbd1c852 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -225,7 +225,7 @@ template<typename T, typename GetMixIndicesFn> void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn) { threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) { - attribute_math::DefaultPropatationMixer<T> mixer{dst.slice(range)}; + attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)}; for (const int i_dst : IndexRange(range.size())) { for (const int i_src : get_mix_indices_fn(range[i_dst])) { mixer.mix_in(i_dst, src[i_src]); @@ -437,7 +437,7 @@ static void extrude_mesh_edges(MeshComponent &component, Array<float3> vert_offsets; if (!edge_offsets.is_single()) { vert_offsets.reinitialize(orig_vert_size); - attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets); + attribute_math::DefaultPropagationMixer<float3> mixer(vert_offsets); for (const int i_edge : edge_selection) { const MEdge &edge = orig_edges[i_edge]; const float3 offset = edge_offsets[i_edge]; @@ -583,7 +583,7 @@ static void extrude_mesh_edges(MeshComponent &component, /* Both corners on each vertical edge of the side polygon get the same value, * so there are only two unique values to mix. */ Array<T> side_poly_corner_data(2); - attribute_math::DefaultPropatationMixer<T> mixer{side_poly_corner_data}; + attribute_math::DefaultPropagationMixer<T> mixer{side_poly_corner_data}; const MEdge &duplicate_edge = duplicate_edges[i_edge_selection]; const int new_vert_1 = duplicate_edge.v1; @@ -705,7 +705,7 @@ static void extrude_mesh_face_regions(MeshComponent &component, Array<float3> vert_offsets; if (!poly_offsets.is_single()) { vert_offsets.reinitialize(orig_vert_size); - attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets); + attribute_math::DefaultPropagationMixer<float3> mixer(vert_offsets); for (const int i_poly : poly_selection) { const MPoly &poly = orig_polys[i_poly]; const float3 offset = poly_offsets[i_poly]; diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 43dbf5060bd..02ac54f4b2b 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -166,6 +166,7 @@ void register_node_tree_type_sh() tt->type = NTREE_SHADER; strcpy(tt->idname, "ShaderNodeTree"); + strcpy(tt->group_idname, "ShaderNodeGroup"); strcpy(tt->ui_name, N_("Shader Editor")); tt->ui_icon = ICON_NODE_MATERIAL; strcpy(tt->ui_description, N_("Shader nodes")); diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index 47df932f9d4..d23561de7ff 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -29,10 +29,9 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, if (out[5].hasoutput) { GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC); } - /* Opti: don't request orco if not needed. */ + /* Optimization: don't request orco if not needed. */ const float val[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : - GPU_attribute(mat, CD_ORCO, ""); + GPUNodeLink *orco_link = out[2].hasoutput ? GPU_attribute(mat, CD_ORCO, "") : GPU_constant(val); const bool success = GPU_stack_link(mat, node, "node_geometry", in, out, orco_link); diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.cc b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc index 11d23e47735..f46556291ce 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hair_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc @@ -23,8 +23,8 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat, { /* Length: don't request length if not needed. */ static const float zero = 0; - GPUNodeLink *length_link = (!out[2].hasoutput) ? GPU_constant(&zero) : - GPU_attribute(mat, CD_HAIRLENGTH, ""); + GPUNodeLink *length_link = out[2].hasoutput ? GPU_attribute(mat, CD_HAIRLENGTH, "") : + GPU_constant(&zero); return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link); } diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb.cc index 38acfab322f..3d28f5278a2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc @@ -17,11 +17,12 @@ static void node_declare(NodeDeclarationBuilder &b) static int gpu_shader_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, + GPUNodeStack * /*in*/, GPUNodeStack *out) { - GPUNodeLink *link = GPU_uniformbuf_link_out(mat, node, out, 0); - return GPU_stack_link(mat, node, "set_rgba", in, out, link); + const bNodeSocket *socket = static_cast<bNodeSocket *>(node->outputs.first); + float *value = static_cast<bNodeSocketValueRGBA *>(socket->default_value)->value; + return GPU_link(mat, "set_rgba", GPU_uniform(value), &out->link); } } // namespace blender::nodes::node_shader_rgb_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index fb5971021fc..0a28b34902e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -41,9 +41,9 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) : GPU_uniform(&dummy_matrix[0][0]); - /* Opti: don't request orco if not needed. */ + /* Optimization: don't request orco if not needed. */ float4 zero(0.0f); - GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(zero) : GPU_attribute(mat, CD_ORCO, ""); + GPUNodeLink *orco = out[0].hasoutput ? GPU_attribute(mat, CD_ORCO, "") : GPU_constant(zero); GPUNodeLink *mtface = GPU_attribute(mat, CD_AUTO_FROM_NAME, ""); GPU_stack_link(mat, node, "node_tex_coord", in, out, inv_obmat, orco, mtface); diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 362cdf58052..14dbb3b25eb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -17,11 +17,12 @@ static void sh_node_value_declare(NodeDeclarationBuilder &b) static int gpu_shader_value(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, + GPUNodeStack * /*in*/, GPUNodeStack *out) { - GPUNodeLink *link = GPU_uniformbuf_link_out(mat, node, out, 0); - return GPU_stack_link(mat, node, "set_value", in, out, link); + const bNodeSocket *socket = static_cast<bNodeSocket *>(node->outputs.first); + float value = static_cast<bNodeSocketValueFloat *>(socket->default_value)->value; + return GPU_link(mat, "set_value", GPU_uniform(&value), &out->link); } static void sh_node_value_build_multi_function(NodeMultiFunctionBuilder &builder) diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 5bed54ebfd7..2ccdf4c0bc9 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -15,6 +15,7 @@ set(INC ../../render ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 03dc61af9a2..ac105b5bcb9 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -140,6 +140,7 @@ void register_node_tree_type_tex(void) tt->type = NTREE_TEXTURE; strcpy(tt->idname, "TextureNodeTree"); + strcpy(tt->group_idname, "TextureNodeGroup"); strcpy(tt->ui_name, N_("Texture Node Editor")); tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */ strcpy(tt->ui_description, N_("Texture nodes")); diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c index 33d9ff0b041..9bb2a9137f4 100644 --- a/source/blender/python/gpu/gpu_py_framebuffer.c +++ b/source/blender/python/gpu/gpu_py_framebuffer.c @@ -686,7 +686,7 @@ static struct PyMethodDef pygpu_framebuffer__tp_methods[] = { PyDoc_STRVAR(pygpu_framebuffer__tp_doc, ".. class:: GPUFrameBuffer(depth_slot=None, color_slots=None)\n" "\n" - " This object gives access to framebuffer functionallities.\n" + " This object gives access to framebuffer functionalities.\n" " When a 'layer' is specified in a argument, a single layer of a 3D or array " "texture is attached to the frame-buffer.\n" " For cube map textures, layer is translated into a cube map face.\n" diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index 656024ae22c..b877e3ceb98 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -55,6 +55,34 @@ static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self)) return PyUnicode_FromString(GPU_platform_version()); } +PyDoc_STRVAR( + pygpu_platform_device_type_get_doc, + ".. function:: device_type_get()\n" + "\n" + " Get GPU device type.\n" + "\n" + " :return: Device type ('APPLE', 'NVIDIA', 'AMD', 'INTEL', 'SOFTWARE', 'UNKNOWN').\n" + " :rtype: str\n"); +static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self)) +{ + if (GPU_type_matches(GPU_DEVICE_APPLE, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("APPLE"); + } + if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("NVIDIA"); + } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("AMD"); + } + if (GPU_type_matches(GPU_DEVICE_INTEL | GPU_DEVICE_INTEL_UHD, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("INTEL"); + } + if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("SOFTWARE"); + } + return PyUnicode_FromString("UNKNOWN"); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -74,6 +102,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = { (PyCFunction)pygpu_platform_version_get, METH_NOARGS, pygpu_platform_version_get_doc}, + {"device_type_get", + (PyCFunction)pygpu_platform_device_type_get, + METH_NOARGS, + pygpu_platform_device_type_get_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c index ac050128a1d..ab2ff59a689 100644 --- a/source/blender/python/gpu/gpu_py_vertex_buffer.c +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -292,7 +292,7 @@ static PyObject *pygpu_vertbuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, Py const char *name = PyUnicode_AsUTF8(identifier); id = GPU_vertformat_attr_id_get(format, name); if (id == -1) { - PyErr_SetString(PyExc_ValueError, "Unknown attribute name"); + PyErr_Format(PyExc_ValueError, "Unknown attribute '%s'", name); return NULL; } } diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 7a36020cea5..6cbd21d0abe 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/memutil + ../bmesh # for writefile.c: dna_type_offsets.h ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 5e7fe4678f6..d90259c0cde 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5174,7 +5174,7 @@ static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent & return false; } - const wmEvent &last_event = *reinterpret_cast<const wmEvent *>(win->event_queue.last); + const wmEvent &last_event = *static_cast<const wmEvent *>(win->event_queue.last); return wm_event_is_same_key_press(last_event, event); } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index a1ebe1fc76f..a5690b52a5a 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1367,6 +1367,10 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt event.xy[0] = ddd->x; event.xy[1] = ddd->y; + /* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't) + * Write this into the event state. */ + copy_v2_v2_int(win->eventstate->xy, event.xy); + event.flag = 0; /* No context change! C->wm->windrawable is drawable, or for area queues. */ |